]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15871 : dotdash/rust/unnamed_fmtstr, r=pcwalton
authorbors <bors@rust-lang.org>
Tue, 22 Jul 2014 09:01:17 +0000 (09:01 +0000)
committerbors <bors@rust-lang.org>
Tue, 22 Jul 2014 09:01:17 +0000 (09:01 +0000)
118 files changed:
Makefile.in
configure
mk/docs.mk
mk/grammar.mk [new file with mode: 0644]
mk/main.mk
mk/tests.mk
src/doc/guide.md
src/etc/vim/syntax/rust.vim
src/grammar/.gitignore [new file with mode: 0644]
src/grammar/README.md [new file with mode: 0644]
src/grammar/RustLexer.g4 [new file with mode: 0644]
src/grammar/check.sh [new file with mode: 0755]
src/grammar/raw-string-literal-ambiguity.md [new file with mode: 0644]
src/grammar/verify.rs [new file with mode: 0644]
src/libcollections/bitv.rs
src/libcollections/hash/sip.rs
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcore/iter.rs
src/libcore/num/mod.rs
src/libcore/str.rs
src/libcoretest/char.rs
src/libgetopts/lib.rs
src/libgraphviz/lib.rs
src/libgreen/macros.rs
src/libnative/io/tty_win32.rs
src/librand/distributions/gamma.rs
src/libregex/lib.rs
src/libregex/test/tests.rs
src/libregex_macros/lib.rs
src/librlibc/lib.rs
src/librustc/driver/config.rs
src/librustc/driver/driver.rs
src/librustc/driver/mod.rs
src/librustc/front/std_inject.rs
src/librustc/front/test.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/privacy.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/typeck/infer/test.rs
src/librustc/plugin/load.rs
src/librustdoc/core.rs
src/librustdoc/lib.rs
src/librustdoc/markdown.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/librustrt/util.rs
src/libserialize/base64.rs
src/libserialize/hex.rs
src/libstd/ascii.rs
src/libstd/collections/hashmap.rs
src/libstd/fmt.rs
src/libstd/io/buffered.rs
src/libstd/io/fs.rs
src/libstd/io/mem.rs
src/libstd/io/mod.rs
src/libstd/lib.rs
src/libstd/num/strconv.rs
src/libstd/path/windows.rs
src/libstd/prelude.rs
src/libstd/task.rs
src/libstd/to_str.rs [deleted file]
src/libstd/to_string.rs [new file with mode: 0644]
src/libsyntax/ast.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/format.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/fold.rs
src/libtest/lib.rs
src/libtime/lib.rs
src/libunicode/u_str.rs
src/libuuid/lib.rs
src/llvm
src/rustllvm/llvm-auto-clean-trigger
src/test/bench/core-std.rs
src/test/bench/msgsend-ring-mutex-arcs.rs
src/test/bench/msgsend-ring-rw-arcs.rs
src/test/bench/noise.rs
src/test/compile-fail/lint-dead-code-3.rs
src/test/pretty/block-comment-wchar.pp
src/test/pretty/block-comment-wchar.rs
src/test/run-pass/byte-literals.rs
src/test/run-pass/class-cast-to-trait-cross-crate-2.rs
src/test/run-pass/default-method-supertrait-vtable.rs
src/test/run-pass/ifmt.rs
src/test/run-pass/issue-12582.rs
src/test/run-pass/issue-13027.rs
src/test/run-pass/issue-15793.rs [new file with mode: 0644]
src/test/run-pass/issue-2185.rs
src/test/run-pass/issue-2718.rs
src/test/run-pass/issue-3683.rs
src/test/run-pass/issue-4759-1.rs
src/test/run-pass/issue-5280.rs
src/test/run-pass/issue-5321-immediates-with-bare-self.rs
src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs
src/test/run-pass/lint-non-camel-case-types-non-uppercase-statics-unicode.rs
src/test/run-pass/macro-deep_expansion.rs [new file with mode: 0644]
src/test/run-pass/match-range.rs
src/test/run-pass/multibyte.rs
src/test/run-pass/raw-str.rs
src/test/run-pass/send_str_treemap.rs
src/test/run-pass/shebang.rs
src/test/run-pass/struct-return.rs
src/test/run-pass/trait-to-str.rs
src/test/run-pass/trait-with-bounds-default.rs
src/test/run-pass/traits-default-method-self.rs
src/test/run-pass/traits-default-method-trivial.rs
src/test/run-pass/unsized.rs
src/test/run-pass/unsized2.rs
src/test/run-pass/utf8-bom.rs
src/test/run-pass/utf8.rs
src/test/run-pass/utf8_chars.rs
src/test/run-pass/utf8_idents.rs

index a8a63a42066b9a9e9e4265f4104c5bf6520ba55d..5683eb7ba06af964def14409de5347f4872ffe3c 100644 (file)
@@ -216,6 +216,7 @@ ifneq ($(strip $(findstring check,$(MAKECMDGOALS)) \
                $(findstring tidy,$(MAKECMDGOALS))),)
   CFG_INFO := $(info cfg: including test rules)
   include $(CFG_SRC_DIR)mk/tests.mk
+  include $(CFG_SRC_DIR)mk/grammar.mk
 endif
 
 # Performance and benchmarking
index 135bdcd3782f06d54435328ab53e2e4f7f56bd86..b6513cb0f74c6424a6f00ea6d2556bcf5baade55 100755 (executable)
--- a/configure
+++ b/configure
@@ -493,6 +493,9 @@ probe CFG_VALGRIND         valgrind
 probe CFG_PERF             perf
 probe CFG_ISCC             iscc
 probe CFG_LLNEXTGEN        LLnextgen
+probe CFG_JAVAC            javac
+probe CFG_ANTLR4           antlr4
+probe CFG_GRUN             grun
 probe CFG_PANDOC           pandoc
 probe CFG_PDFLATEX         pdflatex
 probe CFG_XELATEX          xelatex
index 933a0bdc717cafb6fb2726b0876438deabb4cdc1..b81851e93c0b30cc455fb166bc0607d71b60a712 100644 (file)
@@ -112,8 +112,8 @@ HTML_DEPS += doc/version_info.html
 doc/version_info.html: $(D)/version_info.html.template $(MKFILE_DEPS) \
                        $(wildcard $(D)/*.*) | doc/
        @$(call E, version-info: $@)
-       $(Q)sed -e "s/VERSION/$(CFG_RELEASE)/; s/SHORT_HASH/$(shell echo \
-                    $(CFG_VER_HASH) | head -c 8)/;\
+       $(Q)sed -e "s/VERSION/$(CFG_RELEASE)/; s/SHORT_HASH/$(\
+                    CFG_SHORT_VER_HASH)/;\
                 s/STAMP/$(CFG_VER_HASH)/;" $< >$@
 
 GENERATED += doc/version.tex doc/version_info.html
diff --git a/mk/grammar.mk b/mk/grammar.mk
new file mode 100644 (file)
index 0000000..c0afa3e
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+BG = $(CFG_BUILD_DIR)/grammar/
+SG = $(S)src/grammar/
+B = $(CFG_BUILD_DIR)/$(CFG_BUILD)/stage2/
+L = $(B)lib/rustlib/$(CFG_BUILD)/lib
+LD = $(CFG_BUILD)/stage2/lib/rustlib/$(CFG_BUILD)/lib/
+RUSTC = $(B)bin/rustc
+
+# Run the reference lexer against libsyntax and compare the tokens and spans.
+# If "// ignore-lexer-test" is present in the file, it will be ignored.
+#
+# $(1) is the file to test.
+define LEXER_TEST
+grep "// ignore-lexer-test" $(1) ; \
+  if [ $$? -eq 1 ]; then \
+   CLASSPATH=$(B)grammar $(CFG_GRUN) RustLexer tokens -tokens < $(1) \
+   | $(B)grammar/verify $(1) ; \
+  fi
+endef
+
+$(BG):
+       $(Q)mkdir -p $(BG)
+
+$(BG)RustLexer.class: $(SG)RustLexer.g4
+       $(Q)$(CFG_ANTLR4) -o $(B)grammar $(SG)RustLexer.g4
+       $(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java
+
+$(BG)verify: $(SG)verify.rs rustc-stage2-H-$(CFG_BUILD) $(LD)stamp.regex_macros $(LD)stamp.rustc
+       $(Q)$(RUSTC) -O --out-dir $(BG) -L $(L) $(SG)verify.rs
+
+check-lexer: $(BG) $(BG)RustLexer.class $(BG)verify
+ifdef CFG_JAVAC
+ifdef CFG_ANTLR4
+ifdef CFG_GRUN
+       $(info Verifying libsyntax against the reference lexer ...)
+       $(Q)$(SG)check.sh $(S) "$(BG)" \
+               "$(CFG_GRUN)" "$(BG)verify" "$(BG)RustLexer.tokens"
+else
+$(info grun not available, skipping lexer test...)
+endif
+else
+$(info antlr4 not available, skipping lexer test...)
+endif
+else
+$(info javac not available, skipping lexer test...)
+endif
index 15e9897d47dbde634b43a1a2d7b42d2dd10487da..98b83530c8de05bced2bde3a80910e8b2d80617d 100644 (file)
@@ -46,7 +46,8 @@ ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT))),)
 ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT_DIR))),)
     CFG_VER_DATE = $(shell git --git-dir='$(CFG_GIT_DIR)' log -1 --pretty=format:'%ci')
     CFG_VER_HASH = $(shell git --git-dir='$(CFG_GIT_DIR)' rev-parse HEAD)
-    CFG_VERSION += ($(CFG_VER_HASH) $(CFG_VER_DATE))
+    CFG_SHORT_VER_HASH = $(shell git --git-dir='$(CFG_GIT_DIR)' rev-parse --short=9 HEAD)
+    CFG_VERSION += ($(CFG_SHORT_VER_HASH) $(CFG_VER_DATE))
 endif
 endif
 
index d2e4388521ecd7730a30f169d2795994ebe219a2..2e500ffeb0a5057e5cff35027c7f21360a44c245 100644 (file)
@@ -192,6 +192,8 @@ check-docs: cleantestlibs cleantmptestlogs check-stage2-docs
 # NOTE: Remove after reprogramming windows bots
 check-fast: check-lite
 
+check-syntax: check-lexer
+
 .PHONY: cleantmptestlogs cleantestlibs
 
 cleantmptestlogs:
index 0175817e66a7ea69835e74e4e50ede936aeac1ea..e3acb0575d226c07c47fe089742d3cb48da17db7 100644 (file)
@@ -18,8 +18,9 @@ something special, and we hope you do too.
 
 To show you how to get going with Rust, we're going to write the traditional
 "Hello, World!" program. Next, we'll introduce you to a tool that's useful for
-writing real-world Rust programs and libraries: "Cargo." Then, we'll show off
-Rust's features by writing a little program together.
+writing real-world Rust programs and libraries: "Cargo." After that, we'll talk
+about the basics of Rust, write a little program to try them out, and then learn
+more advanced things.
 
 Sound good? Let's go!
 
@@ -357,70 +358,9 @@ That's it! We've successfully built `hello_world` with Cargo. Even though our
 program is simple, it's using much of the real tooling that you'll use for the
 rest of your Rust career.
 
-Next, we'll learn more about Rust itself, by starting to write a more complicated
-program. We hope you want to do more with Rust than just print "Hello, world!"
-
-## Guessing Game
-
-Let's write a bigger program in Rust. We could just go through a laundry list
-of Rust features, but that's boring. Instead, we'll learn more about how to
-code in Rust by writing a few example projects.
-
-For our first project, we'll implement a classic beginner programming problem:
-the guessing game. Here's how it works: Our program will generate a random
-integer between one and a hundred. It will then prompt us to enter a guess.
-Upon entering our guess, it will tell us if we're too low or too high. Once we
-guess correctly, it will congratulate us, and print the number of guesses we've
-taken to the screen. Sound good? It sounds easy, but it'll end up showing off a
-number of basic features of Rust.
-
-### Set up
-
-Let's set up a new project. Go to your projects directory, and make a new
-directory for the project, as well as a `src` directory for our code:
-
-```{bash}
-$ cd ~/projects
-$ mkdir guessing_game
-$ cd guessing_game
-$ mkdir src
-```
-
-Great. Next, let's make a `Cargo.toml` file so Cargo knows how to build our
-project:
-
-```{ignore}
-[package]
-
-name = "guessing_game"
-version = "0.1.0"
-authors = [ "someone@example.com" ]
-
-[[bin]]
-
-name = "guessing_game"
-```
-
-Finally, we need our source file. Let's just make it hello world for now, so we
-can check that our setup works. In `src/guessing_game.rs`:
-
-```{rust}
-fn main() {
-    println!("Hello world!");
-}
-```
-
-Let's make sure that worked:
-
-```{bash}
-$ cargo build
-   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
-$
-```
-
-Excellent! Open up your `src/guessing_game.rs` again. We'll be writing all of
-our code in this file. The next section of the tutorial will show you how to
-build multiple-file projects.
+Now that you've got the tools down, let's actually learn more about the Rust
+language itself. These are the basics that will serve you well through the rest
+of your time with Rust.
 
 ## Variable bindings
 
@@ -1143,25 +1083,31 @@ can only be _one_ of `Less`, `Equal`, or `Greater` at any given time. Here's
 an example:
 
 ```rust
-let x = 5i;
-let y = 10i;
+fn cmp(a: int, b: int) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
 
-let ordering = x.cmp(&y);
+fn main() {
+    let x = 5i;
+    let y = 10i;
 
-if ordering == Less {
-    println!("less");
-} else if ordering == Greater {
-    println!("greater");
-} else if ordering == Equal {
-    println!("equal");
+    let ordering = cmp(x, y);
+
+    if ordering == Less {
+        println!("less");
+    } else if ordering == Greater {
+        println!("greater");
+    } else if ordering == Equal {
+        println!("equal");
+    }
 }
 ```
 
-`cmp` is a function that compares two things, and returns an `Ordering`. The
-call looks a little bit strange: rather than `cmp(x, y)`, we say `x.cmp(&y)`.
-We haven't covered methods and references yet, so it should look a little bit
-foreign. Right now, just pretend it says `cmp(x, y)`, and we'll get to those
-details soon.
+`cmp` is a function that compares two things, and returns an `Ordering`. We
+return either `Less`, `Greater`, or `Equal`, depending on if the two values
+are greater, less, or equal.
 
 The `ordering` variable has the type `Ordering`, and so contains one of the
 three values. We can then do a bunch of `if`/`else` comparisons to check
@@ -1172,12 +1118,12 @@ that not only makes them nicer to read, but also makes sure that you never
 miss a case. Before we get to that, though, let's talk about another kind of
 enum: one with values.
 
-This enum has two variants, one of which has a value.:
+This enum has two variants, one of which has a value:
 
-```
+```{rust}
 enum OptionalInt {
     Value(int),
-    Missing
+    Missing,
 }
 
 fn main() {
@@ -1261,30 +1207,46 @@ for every possible value of `x`, and so our program will now compile.
 section on enums?
 
 ```{rust}
-let x = 5i;
-let y = 10i;
+fn cmp(a: int, b: int) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
 
-let ordering = x.cmp(&y);
+fn main() {
+    let x = 5i;
+    let y = 10i;
+
+    let ordering = cmp(x, y);
 
-if ordering == Less {
-    println!("less");
-} else if ordering == Greater {
-    println!("greater");
-} else if ordering == Equal {
-    println!("equal");
+    if ordering == Less {
+        println!("less");
+    } else if ordering == Greater {
+        println!("greater");
+    } else if ordering == Equal {
+        println!("equal");
+    }
 }
 ```
 
 We can re-write this as a `match`:
 
 ```{rust}
-let x = 5i;
-let y = 10i;
+fn cmp(a: int, b: int) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+
+fn main() {
+    let x = 5i;
+    let y = 10i;
 
-match x.cmp(&y) {
-    Less    => println!("less"),
-    Greater => println!("greater"),
-    Equal   => println!("equal"),
+    match cmp(x, y) {
+        Less    => println!("less"),
+        Greater => println!("greater"),
+        Equal   => println!("equal"),
+    }
 }
 ```
 
@@ -1297,17 +1259,25 @@ make sure to cover all of our bases.
 `match` is also an expression, which means we can use it on the right hand side
 of a `let` binding. We could also implement the previous line like this:
 
-```
-let x = 5i;
-let y = 10i;
+```{rust}
+fn cmp(a: int, b: int) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
 
-let result = match x.cmp(&y) {
-    Less    => "less",
-    Greater => "greater",
-    Equal   => "equal",
-};
+fn main() {
+    let x = 5i;
+    let y = 10i;
+
+    let result = match cmp(x, y) {
+        Less    => "less",
+        Greater => "greater",
+        Equal   => "equal",
+    };
 
-println!("{}", result);
+    println!("{}", result);
+}
 ```
 
 In this case, it doesn't make a lot of sense, as we are just making a temporary
@@ -1463,6 +1433,8 @@ we haven't seen before. Here's a simple program that reads some input,
 and then prints it back out:
 
 ```{rust,ignore}
+use std::io;
+
 fn main() {
     println!("Type something!");
 
@@ -1474,7 +1446,7 @@ fn main() {
 
 Let's go over these chunks, one by one:
 
-```{rust}
+```{rust,ignore}
 std::io::stdin();
 ```
 
@@ -1527,16 +1499,68 @@ a full line of input. Nice and easy.
 .ok().expect("Failed to read line");
 ```
 
-Here's the thing: reading a line from standard input could fail. For example,
-if this program isn't running in a terminal, but is running as part of a cron
-job, or some other context where there's no standard input. So Rust expects us
-to handle this case. Given that we plan on always running this program in a
-terminal, we use the `ok()` method to tell Rust that we're expecting everything
-to be just peachy, and the `expect()` method on that result to give an error
-message if our expectation goes wrong.
+Do you remember this code? 
+
+```
+enum OptionalInt {
+    Value(int),
+    Missing,
+}
+
+fn main() {
+    let x = Value(5);
+    let y = Missing;
+
+    match x {
+        Value(n) => println!("x is {:d}", n),
+        Missing  => println!("x is missing!"),
+    }
+
+    match y {
+        Value(n) => println!("y is {:d}", n),
+        Missing  => println!("y is missing!"),
+    }
+}
+```
+
+We had to match each time, to see if we had a value or not. In this case,
+though, we _know_ that `x` has a `Value`. But `match` forces us to handle
+the `missing` case. This is what we want 99% of the time, but sometimes, we
+know better than the compiler.
+
+Likewise, `read_line()` does not return a line of input. It _might_ return a
+line of input. It might also fail to do so. This could happen if our program
+isn't running in a terminal, but as part of a cron job, or some other context
+where there's no standard input. Because of this, `read_line` returns a type
+very similar to our `OptionalInt`: an `IoResult<T>`. We haven't talked about
+`IoResult<T>` yet because it is the **generic** form of our `OptionalInt`.
+Until then, you can think of it as being the same thing, just for any type, not
+just `int`s.
+
+Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
+same thing as our `match` statement, but assuming that we have a valid value.
+If we don't, it will terminate our program. In this case, if we can't get
+input, our program doesn't work, so we're okay with that. In most cases, we
+would want to handle the error case explicitly. The result of `ok()` has a
+method, `expect()`, which allows us to give an error message if this crash
+happens.
 
 We will cover the exact details of how all of this works later in the Guide.
-For now, this is all you need.
+For now, this gives you enough of a basic understanding to work with.
+
+Back to the code we were working on! Here's a refresher:
+
+```{rust,ignore}
+use std::io;
+
+fn main() {
+    println!("Type something!");
+
+    let input = io::stdin().read_line().ok().expect("Failed to read line");
+
+    println!("{}", input);
+}
+```
 
 With long lines like this, Rust gives you some flexibility with the whitespace.
 We _could_ write the example like this:
@@ -1562,11 +1586,878 @@ here.
 That's all you need to get basic input from the standard input! It's not too
 complicated, but there are a number of small parts.
 
-## Guessing Game: complete
+## Guessing Game
+
+Okay! We've got the basics of Rust down. Let's write a bigger program.
+
+For our first project, we'll implement a classic beginner programming problem:
+the guessing game. Here's how it works: Our program will generate a random
+integer between one and a hundred. It will then prompt us to enter a guess.
+Upon entering our guess, it will tell us if we're too low or too high. Once we
+guess correctly, it will congratulate us, and print the number of guesses we've
+taken to the screen. Sound good?
+
+### Set up
+
+Let's set up a new project. Go to your projects directory, and make a new
+directory for the project, as well as a `src` directory for our code:
+
+```{bash}
+$ cd ~/projects
+$ mkdir guessing_game
+$ cd guessing_game
+$ mkdir src
+```
+
+Great. Next, let's make a `Cargo.toml` file so Cargo knows how to build our
+project:
+
+```{ignore}
+[package]
+
+name = "guessing_game"
+version = "0.1.0"
+authors = [ "someone@example.com" ]
+
+[[bin]]
+
+name = "guessing_game"
+```
+
+Finally, we need our source file. Let's just make it hello world for now, so we
+can check that our setup works. In `src/guessing_game.rs`:
+
+```{rust}
+fn main() {
+    println!("Hello world!");
+}
+```
+
+Let's make sure that worked:
+
+```{bash}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+$
+```
+
+Excellent! Open up your `src/guessing_game.rs` again. We'll be writing all of
+our code in this file. We'll talk about multiple-file projects later on in the
+guide.
+
+### Processing a Guess
+
+Let's get to it! The first thing we need to do for our guessing game is
+allow our player to input a guess. Put this in your `src/guessing_game.rs`:
+
+```{rust,no_run}
+use std::io;
+
+fn main() {
+    println!("Guess the number!");
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+
+    println!("You guessed: {}", input);
+}
+```
+
+You've seen this code before, when we talked about standard input. We
+import the `std::io` module with `use`, and then our `main` function contains
+our program's logic. We print a little message announcing the game, ask the
+user to input a guess, get their input, and then print it out.
+
+Because we talked about this in the section on standard I/O, I won't go into
+more details here. If you need a refresher, go re-read that section.
+
+### Generating a secret number
+
+Next, we need to generate a secret number. To do that, we need to use Rust's
+random number generation, which we haven't talked about yet. Rust includes a
+bunch of interesting functions in its standard library. If you need a bit of
+code, it's possible that it's already been written for you! In this case,
+we do know that Rust has random number generation, but we don't know how to
+use it.
+
+Enter the docs. Rust has a page specifically to document the standard library.
+You can find that page [here](std/index.html). There's a lot of information on
+that page, but the best part is the search bar. Right up at the top, there's
+a box that you can enter in a search term. The search is pretty primitive
+right now, but is getting better all the time. If you type 'random' in that
+box, the page will update to [this
+one](http://doc.rust-lang.org/std/index.html?search=random). The very first
+result is a link to
+[std::rand::random](http://doc.rust-lang.org/std/rand/fn.random.html). If we
+click on that result, we'll be taken to its documentation page.
+
+This page shows us a few things: the type signature of the function, some
+explanatory text, and then an example. Let's modify our code to add in the
+`random` function:
+
+```{rust,ignore}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random() % 100i) + 1i;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+
+
+    println!("You guessed: {}", input);
+}
+```
+
+The first thing we changed was to `use std::rand`, as the docs
+explained.  We then added in a `let` expression to create a variable binding
+named `secret_number`, and we printed out its result. Let's try to compile
+this using `cargo build`:
+
+```{notrust,no_run}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+src/guessing_game.rs:7:26: 7:34 error: the type of this value must be known in this context
+src/guessing_game.rs:7     let secret_number = (rand::random() % 100i) + 1i;
+                                                ^~~~~~~~
+error: aborting due to previous error
+```
+
+It didn't work! Rust says "the type of this value must be known in this
+context." What's up with that? Well, as it turns out, `rand::random()` can
+generate many kinds of random values, not just integers. And in this case, Rust
+isn't sure what kind of value `random()` should generate. So we have to help
+it. With number literals, we just add an `i` onto the end to tell Rust they're
+integers, but that does not work with functions. There's a different syntax,
+and it looks like this:
+
+```{rust,ignore}
+rand::random::<int>();
+```
+
+This says "please give me a random `int` value." We can change our code to use
+this hint...
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<int>() % 100i) + 1i;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+
+
+    println!("You guessed: {}", input);
+}
+```
+
+... and then recompile:
+
+```{notrust,ignore}
+$ cargo build
+  Compiling guessing_game v0.1.0 (file:/home/steve/tmp/guessing_game)
+$
+```
+
+Excellent! Try running our new program a few times:
+
+```{notrust,ignore}
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 7
+Please input your guess.
+4
+You guessed: 4
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 83
+Please input your guess.
+5
+You guessed: 5
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: -29
+Please input your guess.
+42
+You guessed: 42
+```
+
+Wait. Negative 29? We wanted a number between one and a hundred! We have two
+options here: we can either ask `random()` to generate an unsigned integer, which
+can only be positive, or we can use the `abs()` function. Let's go with the
+unsigned integer approach. If we want a random positive number, we should ask for
+a random positive number. Our code looks like this now:
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+
+
+    println!("You guessed: {}", input);
+}
+```
+
+And trying it out:
+
+```{notrust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 57
+Please input your guess.
+3
+You guessed: 3
+```
+
+Great! Next up: let's compare our guess to the secret guess.
+
+### Comparing guesses
+
+If you remember, earlier in the tutorial, we made a `cmp` function that compared
+two numbers. Let's add that in, along with a `match` statement to compare the
+guess to the secret guess:
+
+```{rust,ignore}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+
+
+    println!("You guessed: {}", input);
+
+    match cmp(input, secret_number) { 
+        Less    => println!("Too small!"),
+        Greater => println!("Too big!"),
+        Equal   => { println!("You win!"); },
+    }
+}
+
+fn cmp(a: int, b: int) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+If we try to compile, we'll get some errors:
+
+```{notrust,ignore}
+$ cargo build
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+src/guessing_game.rs:20:15: 20:20 error: mismatched types: expected `int` but found `collections::string::String` (expected int but found struct collections::string::String)
+src/guessing_game.rs:20     match cmp(input, secret_number) {
+                                      ^~~~~
+src/guessing_game.rs:20:22: 20:35 error: mismatched types: expected `int` but found `uint` (expected int but found uint)
+src/guessing_game.rs:20     match cmp(input, secret_number) {
+                                             ^~~~~~~~~~~~~
+error: aborting due to 2 previous errors
+```
+
+This often happens when writing Rust programs, and is one of Rust's greatest
+strengths. You try out some code, see if it compiles, and Rust tells you that
+you've done something wrong. In this case, our `cmp` function works on integers,
+but we've given it unsigned integers. In this case, the fix is easy, because
+we wrote the `cmp` function! Let's change it to take `uint`s:
+
+```{rust,ignore}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+
+
+    println!("You guessed: {}", input);
+
+    match cmp(input, secret_number) {
+        Less    => println!("Too small!"),
+        Greater => println!("Too big!"),
+        Equal   => { println!("You win!"); },
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+And try compiling again:
+
+```{notrust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+src/guessing_game.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
+src/guessing_game.rs:20     match cmp(input, secret_number) {
+                                      ^~~~~
+error: aborting due to previous error
+```
+
+This error is similar to the last one: we expected to get a `uint`, but we got
+a `String` instead! That's because our `input` variable is coming from the
+standard input, and you can guess anything. Try it:
+
+```{notrust,ignore}
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 73
+Please input your guess.
+hello
+You guessed: hello
+```
+
+Oops! Also, you'll note that we just ran our program even though it didn't compile.
+This works because the older version we did successfully compile was still lying
+around. Gotta be careful!
+
+Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's
+a function for that:
+
+```{rust,ignore}
+let input = io::stdin().read_line()
+                       .ok()
+                       .expect("Failed to read line");
+let guess: Option<uint> = from_str(input.as_slice());
+```
+
+The `from_str` function takes in a `&str` value and converts it into something.
+We tell it what kind of something with a type hint. Remember our type hint with
+`random()`? It looked like this:
+
+```{rust,ignore}
+rand::random::<uint>();
+```
+
+There's an alternate way of providing a hint too, and that's declaring the type
+in a `let`:
+
+```{rust,ignore}
+let x: uint = rand::random();
+```
+
+In this case, we say `x` is a `uint` explicitly, so Rust is able to properly
+tell `random()` what to generate. In a similar fashion, both of these work:
+
+```{rust,ignore}
+let guess = from_str::<Option<uint>>("5");
+let guess: Option<uint> = from_str("5");
+```
+
+In this case, I happen to prefer the latter, and in the `random()` case, I prefer
+the former. I think the nested `<>`s make the first option especially ugly and
+a bit harder to read.
+
+Anyway, with us now convering our input to a number, our code looks like this:
+
+```{rust,ignore}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+    let input_num: Option<uint> = from_str(input.as_slice());
+
+
+
+    println!("You guessed: {}", input_num);
+
+    match cmp(input_num, secret_number) {
+        Less    => println!("Too small!"),
+        Greater => println!("Too big!"),
+        Equal   => { println!("You win!"); },
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+Let's try it out!
+
+```{notrust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/steve/tmp/guessing_game)
+src/guessing_game.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
+src/guessing_game.rs:22     match cmp(input_num, secret_number) {
+                                      ^~~~~~~~~
+error: aborting due to previous error
+```
+
+Oh yeah! Our `input_num` has the type `Option<uint>`, rather than `uint`. We
+need to unwrap the Option. If you remember from before, `match` is a great way
+to do that. Try this code:
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+    let input_num: Option<uint> = from_str(input.as_slice());
+
+    let num = match input_num {
+        Some(num) => num,
+        None      => {
+            println!("Please input a number!");
+            return;
+        }
+    };
+
+
+    println!("You guessed: {}", num);
+
+    match cmp(num, secret_number) {
+        Less    => println!("Too small!"),
+        Greater => println!("Too big!"),
+        Equal   => { println!("You win!"); },
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+We use a `match` to either give us the `uint` inside of the `Option`, or we
+print an error message and return. Let's give this a shot:
+
+```{notrust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 17
+Please input your guess.
+5
+Please input a number!
+$
+```
+
+Uh, what? But we did!
+
+... actually, we didn't. See, when you get a line of input from `stdin()`,
+you get all the input. Including the `\n` character from you pressing Enter.
+So, `from_str()` sees the string `"5\n"` and says "nope, that's not a number,
+there's non-number stuff in there!" Luckily for us, `&str`s have an easy
+method we can use defined on them: `trim()`. One small modification, and our
+code looks like this:
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    println!("Please input your guess.");
+
+    let input = io::stdin().read_line()
+                           .ok()
+                           .expect("Failed to read line");
+    let input_num: Option<uint> = from_str(input.as_slice().trim());
+
+    let num = match input_num {
+        Some(num) => num,
+        None      => {
+            println!("Please input a number!");
+            return;
+        }
+    };
+
+
+    println!("You guessed: {}", num);
+
+    match cmp(num, secret_number) {
+        Less    => println!("Too small!"),
+        Greater => println!("Too big!"),
+        Equal   => { println!("You win!"); },
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+Let's try it!
+
+```{notrust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 58
+Please input your guess.
+  76  
+You guessed: 76
+Too big!
+$
+```
+
+Nice! You can see I even added spaces before my guess, and it still figured
+out that I guessed 76. Run the program a few times, and verify that guessing
+the number works, as well as guessing a number too small.
+
+The Rust compiler helped us out quite a bit there! This technique is called
+"lean on the compiler," and it's often useful when working on some code. Let
+the error messages help guide you towards the correct types.
+
+Now we've got most of the game working, but we can only make one guess. Let's
+change that by adding loops!
+
+### Looping
+
+As we already discussed, the `loop` key word gives us an infinite loop. So
+let's add that in:
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    loop {
+
+        println!("Please input your guess.");
+
+        let input = io::stdin().read_line()
+                               .ok()
+                               .expect("Failed to read line");
+        let input_num: Option<uint> = from_str(input.as_slice().trim());
+
+        let num = match input_num {
+            Some(num) => num,
+            None      => {
+                println!("Please input a number!");
+                return;
+            }
+        };
+
+
+        println!("You guessed: {}", num);
+
+        match cmp(num, secret_number) {
+            Less    => println!("Too small!"),
+            Greater => println!("Too big!"),
+            Equal   => { println!("You win!"); },
+        }
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+And try it out. But wait, didn't we just add an infinite loop? Yup. Remember
+that `return`? If we give a non-number answer, we'll `return` and quit. Observe:
+
+```{notrust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+steve@computer:~/tmp/guessing_game$ ./target/guessing_game 
+Guess the number!
+The secret number is: 59
+Please input your guess.
+45
+You guessed: 45
+Too small!
+Please input your guess.
+60
+You guessed: 60
+Too big!
+Please input your guess.
+59
+You guessed: 59
+You win!
+Please input your guess.
+quit
+Please input a number!
+$
+```
+
+Ha! `quit` actually quits. As does any other non-number input. Well, this is
+suboptimal to say the least. First, let's actually quit when you win the game:
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    loop {
+
+        println!("Please input your guess.");
+
+        let input = io::stdin().read_line()
+                               .ok()
+                               .expect("Failed to read line");
+        let input_num: Option<uint> = from_str(input.as_slice().trim());
+
+        let num = match input_num {
+            Some(num) => num,
+            None      => {
+                println!("Please input a number!");
+                return;
+            }
+        };
+
+
+        println!("You guessed: {}", num);
+
+        match cmp(num, secret_number) {
+            Less    => println!("Too small!"),
+            Greater => println!("Too big!"),
+            Equal   => {
+                println!("You win!");
+                return;
+            },
+        }
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+By adding the `return` line after the `You win!`, we'll exit the program when
+we win. We have just one more tweak to make: when someone inputs a non-number,
+we don't want to quit, we just want to ignore it. Change that `return` to
+`continue`:
+
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    println!("The secret number is: {}", secret_number);
+
+    loop {
+
+        println!("Please input your guess.");
+
+        let input = io::stdin().read_line()
+                               .ok()
+                               .expect("Failed to read line");
+        let input_num: Option<uint> = from_str(input.as_slice().trim());
+
+        let num = match input_num {
+            Some(num) => num,
+            None      => {
+                println!("Please input a number!");
+                continue;
+            }
+        };
+
+
+        println!("You guessed: {}", num);
+
+        match cmp(num, secret_number) {
+            Less    => println!("Too small!"),
+            Greater => println!("Too big!"),
+            Equal   => {
+                println!("You win!");
+                return;
+            },
+        }
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+Now we should be good! Let's try:
+
+```{rust,ignore}
+$ cargo build
+   Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game)
+$ ./target/guessing_game 
+Guess the number!
+The secret number is: 61
+Please input your guess.
+10
+You guessed: 10
+Too small!
+Please input your guess.
+99
+You guessed: 99
+Too big!
+Please input your guess.
+foo
+Please input a number!
+Please input your guess.
+61
+You guessed: 61
+You win!
+```
+
+Awesome! With one tiny last tweak, we have finished the guessing game. Can you
+think of what it is? That's right, we don't want to print out the secret number.
+It was good for testing, but it kind of ruins the game. Here's our final source:
+
+```{rust,no_run}
+use std::io;
+use std::rand;
+
+fn main() {
+    println!("Guess the number!");
+
+    let secret_number = (rand::random::<uint>() % 100u) + 1u;
+
+    loop {
+
+        println!("Please input your guess.");
+
+        let input = io::stdin().read_line()
+                               .ok()
+                               .expect("Failed to read line");
+        let input_num: Option<uint> = from_str(input.as_slice().trim());
+
+        let num = match input_num {
+            Some(num) => num,
+            None      => {
+                println!("Please input a number!");
+                continue;
+            }
+        };
+
+
+        println!("You guessed: {}", num);
+
+        match cmp(num, secret_number) {
+            Less    => println!("Too small!"),
+            Greater => println!("Too big!"),
+            Equal   => {
+                println!("You win!");
+                return;
+            },
+        }
+    }
+}
+
+fn cmp(a: uint, b: uint) -> Ordering {
+    if a < b { Less }
+    else if a > b { Greater }
+    else { Equal }
+}
+```
+
+### Complete!
 
 At this point, you have successfully built the Guessing Game! Congratulations!
-For reference, [We've placed the sample code on
-GitHub](https://github.com/steveklabnik/guessing_game).
 
 You've now learned the basic syntax of Rust. All of this is relatively close to
 various other programming languages you have used in the past. These
index 1b75538d2f71b04b24d6f32e17fbd5e3d7681edc..e3fadccd1c9fde65979b0aa169f978b16b2f497f 100644 (file)
@@ -3,7 +3,7 @@
 " Maintainer:   Patrick Walton <pcwalton@mozilla.com>
 " Maintainer:   Ben Blum <bblum@cs.cmu.edu>
 " Maintainer:   Chris Morgan <me@chrismorgan.info>
-" Last Change:  July 06, 2014
+" Last Change:  July 18, 2014
 
 if version < 600
   syntax clear
@@ -38,7 +38,7 @@ syn keyword   rustKeyword     for in if impl let
 syn keyword   rustKeyword     loop once proc pub
 syn keyword   rustKeyword     return super
 syn keyword   rustKeyword     unsafe virtual while
-syn keyword   rustKeyword     use nextgroup=rustModPath skipwhite skipempty
+syn keyword   rustKeyword     use nextgroup=rustModPath,rustModPathInUse skipwhite skipempty
 " FIXME: Scoped impl's name is also fallen in this category
 syn keyword   rustKeyword     mod trait struct enum type nextgroup=rustIdentifier skipwhite skipempty
 syn keyword   rustStorage     mut ref static const
@@ -60,6 +60,10 @@ syn region    rustBoxPlacementBalance start="(" end=")" containedin=rustBoxPlace
 syn region    rustBoxPlacementBalance start="\[" end="\]" containedin=rustBoxPlacement transparent
 " {} are handled by rustFoldBraces
 
+syn region rustMacroRepeat matchgroup=rustMacroRepeatDelimiters start="$(" end=")" contains=TOP nextgroup=rustMacroRepeatCount
+syn match rustMacroRepeatCount ".\?[*+]" contained
+syn match rustMacroVariable "$\w\+"
+
 " Reserved (but not yet used) keywords {{{2
 syn keyword   rustReservedKeyword alignof be do offsetof priv pure sizeof typeof unsized yield
 
@@ -138,8 +142,9 @@ syn keyword   rustBoolean     true false
 " If foo::bar changes to foo.bar, change this ("::" to "\.").
 " If foo::bar changes to Foo::bar, change this (first "\w" to "\u").
 syn match     rustModPath     "\w\(\w\)*::[^<]"he=e-3,me=e-3
-syn match     rustModPath     "\w\(\w\)*" contained " only for 'use path;'
+syn match     rustModPathInUse "\w\(\w\)*" contained " only for 'use path;'
 syn match     rustModPathSep  "::"
+" rustModPathInUse is split out from rustModPath so that :syn-include can get the group list right.
 
 syn match     rustFuncCall    "\w\(\w\)*("he=e-1,me=e-1
 syn match     rustFuncCall    "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>();
@@ -233,6 +238,9 @@ hi def link rustBinNumber       rustNumber
 hi def link rustIdentifierPrime rustIdentifier
 hi def link rustTrait           rustType
 
+hi def link rustMacroRepeatCount   rustMacroRepeatDelimiters
+hi def link rustMacroRepeatDelimiters   Macro
+hi def link rustMacroVariable Define
 hi def link rustSigil         StorageClass
 hi def link rustEscape        Special
 hi def link rustEscapeUnicode rustEscape
@@ -255,6 +263,7 @@ hi def link rustReservedKeyword Error
 hi def link rustConditional   Conditional
 hi def link rustIdentifier    Identifier
 hi def link rustCapsIdent     rustIdentifier
+hi def link rustModPathInUse  rustModPath
 hi def link rustModPath       Include
 hi def link rustModPathSep    Delimiter
 hi def link rustFunction      Function
diff --git a/src/grammar/.gitignore b/src/grammar/.gitignore
new file mode 100644 (file)
index 0000000..e77db28
--- /dev/null
@@ -0,0 +1,4 @@
+verify
+*.class
+*.java
+*.tokens
diff --git a/src/grammar/README.md b/src/grammar/README.md
new file mode 100644 (file)
index 0000000..f5b872c
--- /dev/null
@@ -0,0 +1,20 @@
+Reference grammar.
+
+Uses [antlr4](http://www.antlr.org/) and a custom Rust tool to compare
+ASTs/token streams generated. You can use the `check-syntax` make target to
+run all of the available tests.
+
+To use manually:
+
+```
+antlr4 RustLexer.g4
+javac *.java
+rustc -O verify.rs
+for file in ../*/**.rs; do
+    echo $file;
+    grun RustLexer tokens -tokens < $file | ./verify $file || break
+done
+```
+
+Note That the `../*/**.rs` glob will match every `*.rs` file in the above
+directory and all of its recursive children. This is a zsh extension.
diff --git a/src/grammar/RustLexer.g4 b/src/grammar/RustLexer.g4
new file mode 100644 (file)
index 0000000..f2705e5
--- /dev/null
@@ -0,0 +1,170 @@
+lexer grammar RustLexer;
+
+tokens {
+    EQ, LT, LE, EQEQ, NE, GE, GT, ANDAND, OROR, NOT, TILDE, PLUT,
+    MINUS, STAR, SLASH, PERCENT, CARET, AND, OR, SHL, SHR, BINOP,
+    BINOPEQ, AT, DOT, DOTDOT, DOTDOTDOT, COMMA, SEMI, COLON,
+    MOD_SEP, RARROW, FAT_ARROW, LPAREN, RPAREN, LBRACKET, RBRACKET,
+    LBRACE, RBRACE, POUND, DOLLAR, UNDERSCORE, LIT_CHAR,
+    LIT_INTEGER, LIT_FLOAT, LIT_STR, LIT_STR_RAW, LIT_BINARY,
+    LIT_BINARY_RAW, IDENT, LIFETIME, WHITESPACE, DOC_COMMENT,
+    COMMENT
+}
+
+/* Note: due to antlr limitations, we can't represent XID_start and
+ * XID_continue properly. ASCII-only substitute. */
+
+fragment XID_start : [_a-zA-Z] ;
+fragment XID_continue : [_a-zA-Z0-9] ;
+
+
+/* Expression-operator symbols */
+
+EQ      : '=' ;
+LT      : '<' ;
+LE      : '<=' ;
+EQEQ    : '==' ;
+NE      : '!=' ;
+GE      : '>=' ;
+GT      : '>' ;
+ANDAND  : '&&' ;
+OROR    : '||' ;
+NOT     : '!' ;
+TILDE   : '~' ;
+PLUS    : '+' ;
+MINUS   : '-' ;
+STAR    : '*' ;
+SLASH   : '/' ;
+PERCENT : '%' ;
+CARET   : '^' ;
+AND     : '&' ;
+OR      : '|' ;
+SHL     : '<<' ;
+SHR     : '>>' ;
+
+BINOP
+    : PLUS
+    | SLASH
+    | MINUS
+    | STAR
+    | PERCENT
+    | CARET
+    | AND
+    | OR
+    | SHL
+    | SHR
+    ;
+
+BINOPEQ : BINOP EQ ;
+
+/* "Structural symbols" */
+
+AT         : '@' ;
+DOT        : '.' ;
+DOTDOT     : '..' ;
+DOTDOTDOT  : '...' ;
+COMMA      : ',' ;
+SEMI       : ';' ;
+COLON      : ':' ;
+MOD_SEP    : '::' ;
+RARROW     : '->' ;
+FAT_ARROW  : '=>' ;
+LPAREN     : '(' ;
+RPAREN     : ')' ;
+LBRACKET   : '[' ;
+RBRACKET   : ']' ;
+LBRACE     : '{' ;
+RBRACE     : '}' ;
+POUND      : '#';
+DOLLAR     : '$' ;
+UNDERSCORE : '_' ;
+
+// Literals
+
+fragment HEXIT
+  : [0-9a-fA-F]
+  ;
+
+fragment CHAR_ESCAPE
+  : [nrt\\'"0]
+  | [xX] HEXIT HEXIT
+  | 'u' HEXIT HEXIT HEXIT HEXIT
+  | 'U' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT
+  ;
+
+LIT_CHAR
+  : '\'' ( '\\' CHAR_ESCAPE | ~[\\'\n\t\r] ) '\''
+  ;
+
+LIT_BYTE
+  : 'b\'' ( '\\' ( [xX] HEXIT HEXIT | [nrt\\'"0] ) | ~[\\'\n\t\r] ) '\''
+  ;
+
+fragment INT_SUFFIX
+  : 'i'
+  | 'i8'
+  | 'i16'
+  | 'i32'
+  | 'i64'
+  | 'u'
+  | 'u8'
+  | 'u16'
+  | 'u32'
+  | 'u64'
+  ;
+
+LIT_INTEGER
+  : [0-9][0-9_]* INT_SUFFIX?
+  | '0b' [01][01_]* INT_SUFFIX?
+  | '0o' [0-7][0-7_]* INT_SUFFIX?
+  | '0x' [0-9a-fA-F][0-9a-fA-F_]* INT_SUFFIX?
+  ;
+
+FLOAT_SUFFIX
+  : 'f32'
+  | 'f64'
+  | 'f128'
+  ;
+
+LIT_FLOAT
+  : [0-9][0-9_]* ('.' | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? FLOAT_SUFFIX?)
+  ;
+
+LIT_STR
+  : '"' ('\\\n' | '\\\r\n' | '\\' CHAR_ESCAPE | .)*? '"'
+  ;
+
+LIT_BINARY : 'b' LIT_STR ;
+LIT_BINARY_RAW : 'rb' LIT_STR_RAW ;
+
+/* this is a bit messy */
+
+fragment LIT_STR_RAW_INNER
+  : '"' .*? '"'
+  | LIT_STR_RAW_INNER2
+  ;
+
+fragment LIT_STR_RAW_INNER2
+  : POUND LIT_STR_RAW_INNER POUND
+  ;
+
+LIT_STR_RAW
+  : 'r' LIT_STR_RAW_INNER
+  ;
+
+IDENT : XID_start XID_continue* ;
+
+LIFETIME : '\'' IDENT ;
+
+WHITESPACE : [ \r\n\t]+ ;
+
+UNDOC_COMMENT     : '////' ~[\r\n]* -> type(COMMENT) ;
+YESDOC_COMMENT    : '///' ~[\r\n]* -> type(DOC_COMMENT) ;
+OUTER_DOC_COMMENT : '//!' ~[\r\n]* -> type(DOC_COMMENT) ;
+LINE_COMMENT      : '//' ~[\r\n]* -> type(COMMENT) ;
+
+DOC_BLOCK_COMMENT
+  : ('/**' ~[*] | '/*!') (DOC_BLOCK_COMMENT | .)*? '*/' -> type(DOC_COMMENT)
+  ;
+
+BLOCK_COMMENT : '/*' (BLOCK_COMMENT | .)*? '*/' -> type(COMMENT) ;
diff --git a/src/grammar/check.sh b/src/grammar/check.sh
new file mode 100755 (executable)
index 0000000..f283631
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Run the reference lexer against libsyntax and compare the tokens and spans.
+# If "// ignore-lexer-test" is present in the file, it will be ignored.
+
+
+# Argument $1 is the file to check, $2 is the classpath to use, $3 is the path
+# to the grun binary, $4 is the path to the verify binary, $5 is the path to
+# RustLexer.tokens
+if [ "${VERBOSE}" == "1" ]; then
+    set -x
+fi
+
+check() {
+    grep --silent "// ignore-lexer-test" $1;
+
+    # if it's *not* found...
+    if [ $? -eq 1 ]; then
+        cd $2 # This `cd` is so java will pick up RustLexer.class. I couldn't
+        # figure out how to wrangle the CLASSPATH, just adding build/grammr didn't
+        # seem to have anny effect.
+        if $3 RustLexer tokens -tokens < $1 | $4 $1 $5; then
+            echo "pass: $1"
+        else
+            echo "fail: $1"
+        fi
+    else
+        echo "skip: $1"
+    fi
+}
+
+for file in $(find $1 -iname '*.rs' ! -path '*/test/compile-fail*'); do
+    check $file $2 $3 $4 $5
+done
diff --git a/src/grammar/raw-string-literal-ambiguity.md b/src/grammar/raw-string-literal-ambiguity.md
new file mode 100644 (file)
index 0000000..6b63bbc
--- /dev/null
@@ -0,0 +1,29 @@
+Rust's lexical grammar is not context-free. Raw string literals are the source
+of the problem. Informally, a raw string literal is an `r`, followed by `N`
+hashes (where N can be zero), a quote, any characters, then a quote followed
+by `N` hashes. This grammar describes this as best possible:
+
+    R -> 'r' S
+    S -> '"' B '"'
+    S -> '#' S '#'
+    B -> . B
+    B -> ε
+
+Where `.` represents any character, and `ε` the empty string. Consider the
+string `r#""#"#`. This string is not a valid raw string literal, but can be
+accepted as one by the above grammar, using the derivation:
+
+    R : #""#"#
+    S : ""#"
+    S : "#
+    B : #
+    B : ε
+
+(Where `T : U` means the rule `T` is applied, and `U` is the remainder of the
+string.) The difficulty arises from the fact that it is fundamentally
+context-sensitive. In particular, the context needed is the number of hashes.
+I know of no way to resolve this, but also have not come up with a proof that
+it is not context sensitive. Such a proof would probably use the pumping lemma
+for context-free languages, but I (cmr) could not come up with a proof after
+spending a few hours on it, and decided my time best spent elsewhere. Pull
+request welcome!
diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs
new file mode 100644 (file)
index 0000000..f2ae5a1
--- /dev/null
@@ -0,0 +1,299 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(globs, phase, macro_rules)]
+
+extern crate syntax;
+extern crate rustc;
+
+#[phase(link)]
+extern crate regex;
+
+#[phase(link, plugin)]
+extern crate log;
+
+#[phase(plugin)] extern crate regex_macros;
+
+use std::collections::HashMap;
+use std::io::File;
+
+use syntax::parse;
+use syntax::parse::lexer;
+use rustc::driver::{session, config};
+
+use syntax::ast;
+use syntax::ast::Name;
+use syntax::parse::token::*;
+use syntax::parse::lexer::TokenAndSpan;
+
+fn parse_token_list(file: &str) -> HashMap<String, Token> {
+    fn id() -> Token {
+        IDENT(ast::Ident { name: Name(0), ctxt: 0, }, false)
+    }
+
+    let mut res = HashMap::new();
+
+    res.insert("-1".to_string(), EOF);
+
+    for line in file.split('\n') {
+        let eq = match line.trim().rfind('=') {
+            Some(val) => val,
+            None => continue
+        };
+
+        let val = line.slice_to(eq);
+        let num = line.slice_from(eq + 1);
+
+        let tok = match val {
+            "SHR" => BINOP(SHR),
+            "DOLLAR" => DOLLAR,
+            "LT" => LT,
+            "STAR" => BINOP(STAR),
+            "FLOAT_SUFFIX" => id(),
+            "INT_SUFFIX" => id(),
+            "SHL" => BINOP(SHL),
+            "LBRACE" => LBRACE,
+            "RARROW" => RARROW,
+            "LIT_STR" => LIT_STR(Name(0)),
+            "DOTDOT" => DOTDOT,
+            "MOD_SEP" => MOD_SEP,
+            "DOTDOTDOT" => DOTDOTDOT,
+            "NOT" => NOT,
+            "AND" => BINOP(AND),
+            "LPAREN" => LPAREN,
+            "ANDAND" => ANDAND,
+            "AT" => AT,
+            "LBRACKET" => LBRACKET,
+            "LIT_STR_RAW" => LIT_STR_RAW(Name(0), 0),
+            "RPAREN" => RPAREN,
+            "SLASH" => BINOP(SLASH),
+            "COMMA" => COMMA,
+            "LIFETIME" => LIFETIME(ast::Ident { name: Name(0), ctxt: 0 }),
+            "CARET" => BINOP(CARET),
+            "TILDE" => TILDE,
+            "IDENT" => id(),
+            "PLUS" => BINOP(PLUS),
+            "LIT_CHAR" => LIT_CHAR(Name(0)),
+            "LIT_BYTE" => LIT_BYTE(Name(0)),
+            "EQ" => EQ,
+            "RBRACKET" => RBRACKET,
+            "COMMENT" => COMMENT,
+            "DOC_COMMENT" => DOC_COMMENT(Name(0)),
+            "DOT" => DOT,
+            "EQEQ" => EQEQ,
+            "NE" => NE,
+            "GE" => GE,
+            "PERCENT" => BINOP(PERCENT),
+            "RBRACE" => RBRACE,
+            "BINOP" => BINOP(PLUS),
+            "POUND" => POUND,
+            "OROR" => OROR,
+            "LIT_INTEGER" => LIT_INTEGER(Name(0)),
+            "BINOPEQ" => BINOPEQ(PLUS),
+            "LIT_FLOAT" => LIT_FLOAT(Name(0)),
+            "WHITESPACE" => WS,
+            "UNDERSCORE" => UNDERSCORE,
+            "MINUS" => BINOP(MINUS),
+            "SEMI" => SEMI,
+            "COLON" => COLON,
+            "FAT_ARROW" => FAT_ARROW,
+            "OR" => BINOP(OR),
+            "GT" => GT,
+            "LE" => LE,
+            "LIT_BINARY" => LIT_BINARY(Name(0)),
+            "LIT_BINARY_RAW" => LIT_BINARY_RAW(Name(0), 0),
+            _ => continue
+        };
+
+        res.insert(num.to_string(), tok);
+    }
+
+    debug!("Token map: {}", res);
+    res
+}
+
+fn str_to_binop(s: &str) -> BinOp {
+    match s {
+        "+" => PLUS,
+        "/" => SLASH,
+        "-" => MINUS,
+        "*" => STAR,
+        "%" => PERCENT,
+        "^" => CARET,
+        "&" => AND,
+        "|" => OR,
+        "<<" => SHL,
+        ">>" => SHR,
+        _ => fail!("Bad binop str `{}`", s)
+    }
+}
+
+/// Assuming a string/binary literal, strip out the leading/trailing
+/// hashes and surrounding quotes/raw/binary prefix.
+fn fix(mut lit: &str) -> ast::Name {
+    if lit.char_at(0) == 'r' {
+        if lit.char_at(1) == 'b' {
+            lit = lit.slice_from(2)
+        } else {
+            lit = lit.slice_from(1);
+        }
+    } else if lit.char_at(0) == 'b' {
+        lit = lit.slice_from(1);
+    }
+
+    let leading_hashes = count(lit);
+
+    // +1/-1 to adjust for single quotes
+    parse::token::intern(lit.slice(leading_hashes + 1, lit.len() - leading_hashes - 1))
+}
+
+/// Assuming a char/byte literal, strip the 'b' prefix and the single quotes.
+fn fixchar(mut lit: &str) -> ast::Name {
+    if lit.char_at(0) == 'b' {
+        lit = lit.slice_from(1);
+    }
+
+    parse::token::intern(lit.slice(1, lit.len() - 1))
+}
+
+fn count(lit: &str) -> uint {
+    lit.chars().take_while(|c| *c == '#').count()
+}
+
+fn parse_antlr_token(s: &str, tokens: &HashMap<String, Token>) -> TokenAndSpan {
+    let re = regex!(
+      r"\[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]"
+    );
+
+    let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice());
+    let start = m.name("start");
+    let end = m.name("end");
+    let toknum = m.name("toknum");
+    let content = m.name("content");
+
+    let proto_tok = tokens.find_equiv(&toknum).expect(format!("didn't find token {} in the map",
+                                                              toknum).as_slice());
+
+    let nm = parse::token::intern(content);
+
+    debug!("What we got: content (`{}`), proto: {}", content, proto_tok);
+
+    let real_tok = match *proto_tok {
+        BINOP(..) => BINOP(str_to_binop(content)),
+        BINOPEQ(..) => BINOPEQ(str_to_binop(content.slice_to(content.len() - 1))),
+        LIT_STR(..) => LIT_STR(fix(content)),
+        LIT_STR_RAW(..) => LIT_STR_RAW(fix(content), count(content)),
+        LIT_CHAR(..) => LIT_CHAR(fixchar(content)),
+        LIT_BYTE(..) => LIT_BYTE(fixchar(content)),
+        DOC_COMMENT(..) => DOC_COMMENT(nm),
+        LIT_INTEGER(..) => LIT_INTEGER(nm),
+        LIT_FLOAT(..) => LIT_FLOAT(nm),
+        LIT_BINARY(..) => LIT_BINARY(nm),
+        LIT_BINARY_RAW(..) => LIT_BINARY_RAW(fix(content), count(content)),
+        IDENT(..) => IDENT(ast::Ident { name: nm, ctxt: 0 }, true),
+        LIFETIME(..) => LIFETIME(ast::Ident { name: nm, ctxt: 0 }),
+        ref t => t.clone()
+    };
+
+    let offset = if real_tok == EOF {
+        1
+    } else {
+        0
+    };
+
+    let sp = syntax::codemap::Span {
+        lo: syntax::codemap::BytePos(from_str::<u32>(start).unwrap() - offset),
+        hi: syntax::codemap::BytePos(from_str::<u32>(end).unwrap() + 1),
+        expn_info: None
+    };
+
+    TokenAndSpan {
+        tok: real_tok,
+        sp: sp
+    }
+}
+
+fn tok_cmp(a: &Token, b: &Token) -> bool {
+    match a {
+        &IDENT(id, _) => match b {
+                &IDENT(id2, _) => id == id2,
+                _ => false
+        },
+        _ => a == b
+    }
+}
+
+fn main() {
+    fn next(r: &mut lexer::StringReader) -> TokenAndSpan {
+        use syntax::parse::lexer::Reader;
+        r.next_token()
+    }
+
+    let args = std::os::args();
+
+    let mut token_file = File::open(&Path::new(args.get(2).as_slice()));
+    let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice());
+
+    let mut stdin = std::io::stdin();
+    let mut antlr_tokens = stdin.lines().map(|l| parse_antlr_token(l.unwrap().as_slice().trim(),
+                                                                   &token_map));
+
+    let code = File::open(&Path::new(args.get(1).as_slice())).unwrap().read_to_string().unwrap();
+    let options = config::basic_options();
+    let session = session::build_session(options, None,
+                                         syntax::diagnostics::registry::Registry::new([]));
+    let filemap = parse::string_to_filemap(&session.parse_sess,
+                                           code,
+                                           String::from_str("<n/a>"));
+    let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);
+
+    for antlr_tok in antlr_tokens {
+        let rustc_tok = next(&mut lexer);
+        if rustc_tok.tok == EOF && antlr_tok.tok == EOF {
+            continue
+        }
+
+        assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
+                antlr_tok);
+
+        macro_rules! matches (
+            ( $($x:pat),+ ) => (
+                match rustc_tok.tok {
+                    $($x => match antlr_tok.tok {
+                        $x => {
+                            if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
+                                // FIXME #15677: needs more robust escaping in
+                                // antlr
+                                warn!("Different names for {} and {}", rustc_tok, antlr_tok);
+                            }
+                        }
+                        _ => fail!("{} is not {}", antlr_tok, rustc_tok)
+                    },)*
+                    ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
+                }
+            )
+        )
+
+        matches!(LIT_BYTE(..),
+            LIT_CHAR(..),
+            LIT_INTEGER(..),
+            LIT_FLOAT(..),
+            LIT_STR(..),
+            LIT_STR_RAW(..),
+            LIT_BINARY(..),
+            LIT_BINARY_RAW(..),
+            IDENT(..),
+            LIFETIME(..),
+            INTERPOLATED(..),
+            DOC_COMMENT(..),
+            SHEBANG(..)
+        );
+    }
+}
index 226da13f9e228b5c33c80a71481738ec67855a0f..f1e9eabe8d1ede1a9fae8f4473243ffcef9c1b57 100644 (file)
@@ -8,6 +8,57 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Collections implemented with bit vectors.
+//!
+//! # Example
+//!
+//! This is a simple example of the [Sieve of Eratosthenes][sieve]
+//! which calculates prime numbers up to a given limit.
+//!
+//! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
+//!
+//! ```
+//! use std::collections::{BitvSet, Bitv};
+//! use std::iter;
+//!
+//! let max_prime = 10000;
+//!
+//! // Store the primes as a BitvSet
+//! let primes = {
+//!     // Assume all numbers are prime to begin, and then we
+//!     // cross off non-primes progressively
+//!     let mut bv = Bitv::with_capacity(max_prime, true);
+//!
+//!     // Neither 0 nor 1 are prime
+//!     bv.set(0, false);
+//!     bv.set(1, false);
+//!
+//!     for i in range(2, max_prime) {
+//!         // if i is a prime
+//!         if bv[i] {
+//!             // Mark all multiples of i as non-prime (any multiples below i * i
+//!             // will have been marked as non-prime previously)
+//!             for j in iter::range_step(i * i, max_prime, i) { bv.set(j, false) }
+//!         }
+//!     }
+//!     BitvSet::from_bitv(bv)
+//! };
+//!
+//! // Simple primality tests below our max bound
+//! let print_primes = 20;
+//! print!("The primes below {} are: ", print_primes);
+//! for x in range(0, print_primes) {
+//!     if primes.contains(&x) {
+//!         print!("{} ", x);
+//!     }
+//! }
+//! println!("");
+//!
+//! // We can manipulate the internal Bitv
+//! let num_primes = primes.get_ref().iter().filter(|x| *x).count();
+//! println!("There are {} primes below {}", num_primes, max_prime);
+//! ```
+
 #![allow(missing_doc)]
 
 use core::prelude::*;
@@ -47,7 +98,7 @@ enum BitvVariant { Big(BigBitv), Small(SmallBitv) }
 /// # Example
 ///
 /// ```rust
-/// use collections::bitv::Bitv;
+/// use collections::Bitv;
 ///
 /// let mut bv = Bitv::with_capacity(10, false);
 ///
@@ -155,13 +206,32 @@ fn mask_words<'a>(&'a self, mut start: uint) -> MaskWords<'a> {
         }
     }
 
-    /// Creates an empty Bitv
+    /// Create an empty Bitv.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    /// let mut bv = Bitv::new();
+    /// ```
     pub fn new() -> Bitv {
         Bitv { storage: Vec::new(), nbits: 0 }
     }
 
-    /// Creates a Bitv that holds `nbits` elements, setting each element
+    /// Create a Bitv that holds `nbits` elements, setting each element
     /// to `init`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(10u, false);
+    /// assert_eq!(bv.len(), 10u);
+    /// for x in bv.iter() {
+    ///     assert_eq!(x, false);
+    /// }
+    /// ```
     pub fn with_capacity(nbits: uint, init: bool) -> Bitv {
         Bitv {
             storage: Vec::from_elem((nbits + uint::BITS - 1) / uint::BITS,
@@ -170,29 +240,24 @@ pub fn with_capacity(nbits: uint, init: bool) -> Bitv {
         }
     }
 
-    /**
-     * Calculates the union of two bitvectors
-     *
-     * Sets `self` to the union of `self` and `v1`. Both bitvectors must be
-     * the same length. Returns `true` if `self` changed.
-    */
-    #[inline]
-    pub fn union(&mut self, other: &Bitv) -> bool {
-        self.process(other, |w1, w2| w1 | w2)
-    }
-
-    /**
-     * Calculates the intersection of two bitvectors
-     *
-     * Sets `self` to the intersection of `self` and `v1`. Both bitvectors
-     * must be the same length. Returns `true` if `self` changed.
-    */
-    #[inline]
-    pub fn intersect(&mut self, other: &Bitv) -> bool {
-        self.process(other, |w1, w2| w1 & w2)
-    }
-
-    /// Retrieve the value at index `i`
+    /// Retrieve the value at index `i`.
+    ///
+    /// # Failure
+    ///
+    /// Assert if `i` out of bounds.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let bv = bitv::from_bytes([0b01100000]);
+    /// assert_eq!(bv.get(0), false);
+    /// assert_eq!(bv.get(1), true);
+    ///
+    /// // Can also use array indexing
+    /// assert_eq!(bv[1], true);
+    /// ```
     #[inline]
     pub fn get(&self, i: uint) -> bool {
         assert!(i < self.nbits);
@@ -202,11 +267,21 @@ pub fn get(&self, i: uint) -> bool {
         x != 0
     }
 
-    /**
-     * Set the value of a bit at a given index
-     *
-     * `i` must be less than the length of the bitvector.
-     */
+    /// Set the value of a bit at a index `i`.
+    ///
+    /// # Failure
+    ///
+    /// Assert if `i` out of bounds.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(5, false);
+    /// bv.set(3, true);
+    /// assert_eq!(bv[3], true);
+    /// ```
     #[inline]
     pub fn set(&mut self, i: uint, x: bool) {
         assert!(i < self.nbits);
@@ -217,33 +292,152 @@ pub fn set(&mut self, i: uint, x: bool) {
                           else { *self.storage.get(w) & !flag };
     }
 
-    /// Set all bits to 1
+    /// Set all bits to 1.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let before = 0b01100000;
+    /// let after  = 0b11111111;
+    ///
+    /// let mut bv = bitv::from_bytes([before]);
+    /// bv.set_all();
+    /// assert_eq!(bv, bitv::from_bytes([after]));
+    /// ```
     #[inline]
     pub fn set_all(&mut self) {
         for w in self.storage.mut_iter() { *w = !0u; }
     }
 
-    /// Flip all bits
+    /// Flip all bits.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let before = 0b01100000;
+    /// let after  = 0b10011111;
+    ///
+    /// let mut bv = bitv::from_bytes([before]);
+    /// bv.negate();
+    /// assert_eq!(bv, bitv::from_bytes([after]));
+    /// ```
     #[inline]
     pub fn negate(&mut self) {
         for w in self.storage.mut_iter() { *w = !*w; }
     }
 
-    /**
-     * Calculate the difference between two bitvectors
-     *
-     * Sets each element of `v0` to the value of that element minus the
-     * element of `v1` at the same index. Both bitvectors must be the same
-     * length.
-     *
-     * Returns `true` if `v0` was changed.
-     */
+    /// Calculate the union of two bitvectors, acts like bitwise or.
+    ///
+    /// Set `self` to the union of `self` and `other`. Both bitvectors must be
+    /// the same length. Return `true` if `self` changed.
+    ///
+    /// # Failure
+    ///
+    /// Assert if the bitvectors are of different length.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01100100;
+    /// let b   = 0b01011010;
+    /// let res = 0b01111110;
+    ///
+    /// let mut a = bitv::from_bytes([a]);
+    /// let b = bitv::from_bytes([b]);
+    ///
+    /// assert!(a.union(&b));
+    /// assert_eq!(a, bitv::from_bytes([res]));
+    /// ```
+    #[inline]
+    pub fn union(&mut self, other: &Bitv) -> bool {
+        self.process(other, |w1, w2| w1 | w2)
+    }
+
+    /// Calculate the intersection of two bitvectors, acts like bitwise and.
+    ///
+    /// Set `self` to the intersection of `self` and `other`. Both bitvectors
+    /// must be the same length. Return `true` if `self` changed.
+    ///
+    /// # Failure
+    ///
+    /// Assert if the bitvectors are of different length.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01100100;
+    /// let b   = 0b01011010;
+    /// let res = 0b01000000;
+    ///
+    /// let mut a = bitv::from_bytes([a]);
+    /// let b = bitv::from_bytes([b]);
+    ///
+    /// assert!(a.intersect(&b));
+    /// assert_eq!(a, bitv::from_bytes([res]));
+    /// ```
+    #[inline]
+    pub fn intersect(&mut self, other: &Bitv) -> bool {
+        self.process(other, |w1, w2| w1 & w2)
+    }
+
+    /// Calculate the difference between two bitvectors.
+    ///
+    /// Set each element of `self` to the value of that element minus the
+    /// element of `other` at the same index. Both bitvectors must be the same
+    /// length. Return `true` if `self` changed.
+    ///
+    /// # Failure
+    ///
+    /// Assert if the bitvectors are of different length.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01100100;
+    /// let b   = 0b01011010;
+    /// let a_b = 0b00100100; // a - b
+    /// let b_a = 0b00011010; // b - a
+    ///
+    /// let mut bva = bitv::from_bytes([a]);
+    /// let bvb = bitv::from_bytes([b]);
+    ///
+    /// assert!(bva.difference(&bvb));
+    /// assert_eq!(bva, bitv::from_bytes([a_b]));
+    ///
+    /// let bva = bitv::from_bytes([a]);
+    /// let mut bvb = bitv::from_bytes([b]);
+    ///
+    /// assert!(bvb.difference(&bva));
+    /// assert_eq!(bvb, bitv::from_bytes([b_a]));
+    /// ```
     #[inline]
     pub fn difference(&mut self, other: &Bitv) -> bool {
         self.process(other, |w1, w2| w1 & !w2)
     }
 
-    /// Returns `true` if all bits are 1
+    /// Returns `true` if all bits are 1.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(5, true);
+    /// assert_eq!(bv.all(), true);
+    ///
+    /// bv.set(1, false);
+    /// assert_eq!(bv.all(), false);
+    /// ```
     #[inline]
     pub fn all(&self) -> bool {
         let mut last_word = !0u;
@@ -254,43 +448,77 @@ pub fn all(&self) -> bool {
         (last_word == ((1 << self.nbits % uint::BITS) - 1) || last_word == !0u)
     }
 
-    /// Returns an iterator over the elements of the vector in order.
+    /// Return an iterator over the elements of the vector in order.
     ///
     /// # Example
     ///
-    /// ```rust
-    /// use collections::bitv::Bitv;
-    /// let mut bv = Bitv::with_capacity(10, false);
-    /// bv.set(1, true);
-    /// bv.set(2, true);
-    /// bv.set(3, true);
-    /// bv.set(5, true);
-    /// bv.set(8, true);
-    /// // Count bits set to 1; result should be 5
-    /// println!("{}", bv.iter().filter(|x| *x).count());
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let bv = bitv::from_bytes([0b01110100, 0b10010010]);
+    /// assert_eq!(bv.iter().filter(|x| *x).count(), 7);
     /// ```
     #[inline]
     pub fn iter<'a>(&'a self) -> Bits<'a> {
         Bits {bitv: self, next_idx: 0, end_idx: self.nbits}
     }
 
-    /// Returns `true` if all bits are 0
+    /// Return `true` if all bits are 0.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(10, false);
+    /// assert_eq!(bv.none(), true);
+    ///
+    /// bv.set(3, true);
+    /// assert_eq!(bv.none(), false);
+    /// ```
     pub fn none(&self) -> bool {
         self.mask_words(0).all(|(_, w)| w == 0)
     }
 
+    /// Return `true` if any bit is 1.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(10, false);
+    /// assert_eq!(bv.any(), false);
+    ///
+    /// bv.set(3, true);
+    /// assert_eq!(bv.any(), true);
+    /// ```
     #[inline]
-    /// Returns `true` if any bit is 1
     pub fn any(&self) -> bool {
         !self.none()
     }
 
-    /**
-     * Organise the bits into bytes, such that the first bit in the
-     * `Bitv` becomes the high-order bit of the first byte. If the
-     * size of the `Bitv` is not a multiple of 8 then trailing bits
-     * will be filled-in with false/0
-     */
+    /// Organise the bits into bytes, such that the first bit in the
+    /// `Bitv` becomes the high-order bit of the first byte. If the
+    /// size of the `Bitv` is not a multiple of 8 then trailing bits
+    /// will be filled-in with `false`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(3, true);
+    /// bv.set(1, false);
+    ///
+    /// assert_eq!(bv.to_bytes(), vec!(0b10100000));
+    ///
+    /// let mut bv = Bitv::with_capacity(9, false);
+    /// bv.set(2, true);
+    /// bv.set(8, true);
+    ///
+    /// assert_eq!(bv.to_bytes(), vec!(0b00100000, 0b10000000));
+    /// ```
     pub fn to_bytes(&self) -> Vec<u8> {
         fn bit (bitv: &Bitv, byte: uint, bit: uint) -> u8 {
             let offset = byte * 8 + bit;
@@ -315,18 +543,37 @@ fn bit (bitv: &Bitv, byte: uint, bit: uint) -> u8 {
         )
     }
 
-    /**
-     * Transform `self` into a `Vec<bool>` by turning each bit into a `bool`.
-     */
+    /// Transform `self` into a `Vec<bool>` by turning each bit into a `bool`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let bv = bitv::from_bytes([0b10100000]);
+    /// assert_eq!(bv.to_bools(), vec!(true, false, true, false,
+    ///                                false, false, false, false));
+    /// ```
     pub fn to_bools(&self) -> Vec<bool> {
         Vec::from_fn(self.nbits, |i| self.get(i))
     }
 
-    /**
-     * Compare a bitvector to a vector of `bool`.
-     *
-     * Both the bitvector and vector must have the same length.
-     */
+    /// Compare a bitvector to a vector of `bool`.
+    /// Both the bitvector and vector must have the same length.
+    /// # Failure
+    ///
+    /// Assert if the bitvectors are of different length.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let bv = bitv::from_bytes([0b10100000]);
+    ///
+    /// assert!(bv.eq_vec([true, false, true, false,
+    ///                    false, false, false, false]));
+    /// ```
     pub fn eq_vec(&self, v: &[bool]) -> bool {
         assert_eq!(self.nbits, v.len());
         let mut i = 0;
@@ -344,12 +591,12 @@ pub fn eq_vec(&self, v: &[bool]) -> bool {
     ///
     /// # Example
     ///
-    /// ```rust
-    /// use collections::bitv::Bitv;
-    /// let mut bvec: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect();
-    /// let expected: Bitv = vec![false, true].iter().map(|n| *n).collect();
-    /// bvec.truncate(2);
-    /// assert_eq!(bvec, expected);
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let mut bv = bitv::from_bytes([0b01001011]);
+    /// bv.truncate(2);
+    /// assert!(bv.eq_vec([false, true]));
     /// ```
     pub fn truncate(&mut self, len: uint) {
         if len < self.len() {
@@ -363,7 +610,18 @@ pub fn truncate(&mut self, len: uint) {
         }
     }
 
-    /// Grows the vector to be able to store `size` bits without resizing
+    /// Grow the vector to be able to store `size` bits without resizing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::with_capacity(3, false);
+    /// bv.reserve(10);
+    /// assert_eq!(bv.len(), 3);
+    /// assert!(bv.capacity() >= 10);
+    /// ```
     pub fn reserve(&mut self, size: uint) {
         let old_size = self.storage.len();
         let size = (size + uint::BITS - 1) / uint::BITS;
@@ -372,24 +630,34 @@ pub fn reserve(&mut self, size: uint) {
         }
     }
 
-    /// Returns the capacity in bits for this bit vector. Inserting any
+    /// Return the capacity in bits for this bit vector. Inserting any
     /// element less than this amount will not trigger a resizing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::new();
+    /// bv.reserve(10);
+    /// assert!(bv.capacity() >= 10);
+    /// ```
     #[inline]
     pub fn capacity(&self) -> uint {
         self.storage.len() * uint::BITS
     }
 
-    /// Grows the `Bitv` in-place.
-    ///
-    /// Adds `n` copies of `value` to the `Bitv`.
+    /// Grow the `Bitv` in-place. Add `n` copies of `value` to the `Bitv`.
     ///
     /// # Example
     ///
-    /// ```rust
-    /// use collections::bitv::Bitv;
-    /// let mut bvec: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect();
-    /// bvec.grow(2, true);
-    /// assert_eq!(bvec, vec![false, true, true, false, true, true].iter().map(|n| *n).collect());
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let mut bv = bitv::from_bytes([0b01001011]);
+    /// bv.grow(2, true);
+    /// assert_eq!(bv.len(), 10);
+    /// assert_eq!(bv.to_bytes(), vec!(0b01001011, 0b11000000));
     /// ```
     pub fn grow(&mut self, n: uint, value: bool) {
         let new_nbits = self.nbits + n;
@@ -420,17 +688,22 @@ pub fn grow(&mut self, n: uint, value: bool) {
         self.nbits = new_nbits;
     }
 
-    /// Shorten a `Bitv` by one, returning the removed element
+    /// Shorten by one and return the removed element.
+    ///
+    /// # Failure
+    ///
+    /// Assert if empty.
     ///
     /// # Example
     ///
-    /// ```rust
-    /// use collections::bitv::Bitv;
-    /// let mut bvec: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect();
-    /// let expected: Bitv = vec![false, true, true].iter().map(|n| *n).collect();
-    /// let popped = bvec.pop();
-    /// assert_eq!(popped, false);
-    /// assert_eq!(bvec, expected);
+    /// ```
+    /// use std::collections::bitv;
+    ///
+    /// let mut bv = bitv::from_bytes([0b01001001]);
+    /// assert_eq!(bv.pop(), true);
+    /// assert_eq!(bv.pop(), false);
+    /// assert_eq!(bv.len(), 6);
+    /// assert_eq!(bv.to_bytes(), vec!(0b01001000));
     /// ```
     pub fn pop(&mut self) -> bool {
         let ret = self.get(self.nbits - 1);
@@ -442,17 +715,17 @@ pub fn pop(&mut self) -> bool {
         ret
     }
 
-    /// Pushes a `bool` onto the `Bitv`
+    /// Push a `bool` onto the end.
     ///
     /// # Example
     ///
-    /// ```rust
-    /// use collections::bitv::Bitv;
-    /// let prototype: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect();
-    /// let mut bvec: Bitv = vec![false, true].iter().map(|n| *n).collect();
-    /// bvec.push(true);
-    /// bvec.push(false);
-    /// assert_eq!(prototype, bvec);
+    /// ```
+    /// use std::collections::Bitv;
+    ///
+    /// let mut bv = Bitv::new();
+    /// bv.push(true);
+    /// bv.push(false);
+    /// assert!(bv.eq_vec([true, false]));
     /// ```
     pub fn push(&mut self, elem: bool) {
         let insert_pos = self.nbits;
@@ -464,11 +737,21 @@ pub fn push(&mut self, elem: bool) {
     }
 }
 
-/**
- * Transform a byte-vector into a `Bitv`. Each byte becomes 8 bits,
- * with the most significant bits of each byte coming first. Each
- * bit becomes `true` if equal to 1 or `false` if equal to 0.
- */
+/// Transform a byte-vector into a `Bitv`. Each byte becomes 8 bits,
+/// with the most significant bits of each byte coming first. Each
+/// bit becomes `true` if equal to 1 or `false` if equal to 0.
+///
+/// # Example
+///
+/// ```
+/// use std::collections::bitv;
+///
+/// let bv = bitv::from_bytes([0b10100000, 0b00010010]);
+/// assert!(bv.eq_vec([true, false, true, false,
+///                    false, false, false, false,
+///                    false, false, false, true,
+///                    false, false, true, false]));
+/// ```
 pub fn from_bytes(bytes: &[u8]) -> Bitv {
     from_fn(bytes.len() * 8, |i| {
         let b = bytes[i / 8] as uint;
@@ -477,10 +760,17 @@ pub fn from_bytes(bytes: &[u8]) -> Bitv {
     })
 }
 
-/**
- * Create a `Bitv` of the specified length where the value at each
- * index is `f(index)`.
- */
+/// Create a `Bitv` of the specified length where the value at each
+/// index is `f(index)`.
+///
+/// # Example
+///
+/// ```
+/// use std::collections::bitv::from_fn;
+///
+/// let bv = from_fn(5, |i| { i % 2 == 0 });
+/// assert!(bv.eq_vec([true, false, true, false, true]));
+/// ```
 pub fn from_fn(len: uint, f: |index: uint| -> bool) -> Bitv {
     let mut bitv = Bitv::with_capacity(len, false);
     for i in range(0u, len) {
@@ -626,11 +916,45 @@ fn idx(&mut self, index: uint) -> Option<bool> {
 }
 
 /// An implementation of a set using a bit vector as an underlying
-/// representation for holding numerical elements.
+/// representation for holding unsigned numerical elements.
 ///
 /// It should also be noted that the amount of storage necessary for holding a
 /// set of objects is proportional to the maximum of the objects when viewed
 /// as a `uint`.
+///
+/// # Example
+///
+/// ```
+/// use std::collections::{BitvSet, Bitv};
+/// use std::collections::bitv;
+///
+/// // It's a regular set
+/// let mut s = BitvSet::new();
+/// s.insert(0);
+/// s.insert(3);
+/// s.insert(7);
+///
+/// s.remove(&7);
+///
+/// if !s.contains(&7) {
+///     println!("There is no 7");
+/// }
+///
+/// // Can initialize from a `Bitv`
+/// let other = BitvSet::from_bitv(bitv::from_bytes([0b11010000]));
+///
+/// s.union_with(&other);
+///
+/// // Print 0, 1, 3 in some order
+/// for x in s.iter() {
+///     println!("{}", x);
+/// }
+///
+/// // Can convert back to a `Bitv`
+/// let bv: Bitv = s.unwrap();
+/// assert!(bv.eq_vec([true, true, false, true,
+///                    false, false, false, false]));
+/// ```
 #[deriving(Clone, PartialEq, Eq)]
 pub struct BitvSet(Bitv);
 
@@ -640,20 +964,49 @@ fn default() -> BitvSet { BitvSet::new() }
 }
 
 impl BitvSet {
-    /// Creates a new bit vector set with initially no contents
+    /// Create a new bit vector set with initially no contents.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// let mut s = BitvSet::new();
+    /// ```
     #[inline]
     pub fn new() -> BitvSet {
         BitvSet(Bitv::new())
     }
 
-    /// Creates a new bit vector set with initially no contents, able to
-    /// hold `nbits` elements without resizing
+    /// Create a new bit vector set with initially no contents, able to
+    /// hold `nbits` elements without resizing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// let mut s = BitvSet::with_capacity(100);
+    /// assert!(s.capacity() >= 100);
+    /// ```
     #[inline]
     pub fn with_capacity(nbits: uint) -> BitvSet {
         BitvSet(Bitv::with_capacity(nbits, false))
     }
 
-    /// Creates a new bit vector set from the given bit vector
+    /// Create a new bit vector set from the given bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{bitv, BitvSet};
+    ///
+    /// let bv = bitv::from_bytes([0b01100000]);
+    /// let s = BitvSet::from_bitv(bv);
+    ///
+    /// // Print 1, 2 in arbitrary order
+    /// for x in s.iter() {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     #[inline]
     pub fn from_bitv(bitv: Bitv) -> BitvSet {
         BitvSet(bitv)
@@ -661,33 +1014,93 @@ pub fn from_bitv(bitv: Bitv) -> BitvSet {
 
     /// Returns the capacity in bits for this bit vector. Inserting any
     /// element less than this amount will not trigger a resizing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    ///
+    /// let mut s = BitvSet::with_capacity(100);
+    /// assert!(s.capacity() >= 100);
+    /// ```
     #[inline]
     pub fn capacity(&self) -> uint {
         let &BitvSet(ref bitv) = self;
         bitv.capacity()
     }
 
-    /// Grows the underlying vector to be able to store `size` bits
+    /// Grows the underlying vector to be able to store `size` bits.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    ///
+    /// let mut s = BitvSet::new();
+    /// s.reserve(10);
+    /// assert!(s.capacity() >= 10);
+    /// ```
     pub fn reserve(&mut self, size: uint) {
         let &BitvSet(ref mut bitv) = self;
         bitv.reserve(size)
     }
 
-    /// Consumes this set to return the underlying bit vector
+    /// Consume this set to return the underlying bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    ///
+    /// let mut s = BitvSet::new();
+    /// s.insert(0);
+    /// s.insert(3);
+    ///
+    /// let bv = s.unwrap();
+    /// assert!(bv.eq_vec([true, false, false, true]));
+    /// ```
     #[inline]
     pub fn unwrap(self) -> Bitv {
         let BitvSet(bitv) = self;
         bitv
     }
 
-    /// Returns a reference to the underlying bit vector
+    /// Return a reference to the underlying bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    ///
+    /// let mut s = BitvSet::new();
+    /// s.insert(0);
+    ///
+    /// let bv = s.get_ref();
+    /// assert_eq!(bv[0], true);
+    /// ```
     #[inline]
     pub fn get_ref<'a>(&'a self) -> &'a Bitv {
         let &BitvSet(ref bitv) = self;
         bitv
     }
 
-    /// Returns a mutable reference to the underlying bit vector
+    /// Return a mutable reference to the underlying bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    ///
+    /// let mut s = BitvSet::new();
+    /// s.insert(0);
+    /// assert_eq!(s.contains(&0), true);
+    /// {
+    ///     // Will free the set during bv's lifetime
+    ///     let bv = s.get_mut_ref();
+    ///     bv.set(0, false);
+    /// }
+    /// assert_eq!(s.contains(&0), false);
+    /// ```
     #[inline]
     pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut Bitv {
         let &BitvSet(ref mut bitv) = self;
@@ -709,8 +1122,25 @@ fn other_op(&mut self, other: &BitvSet, f: |uint, uint| -> uint) {
         }
     }
 
+    /// Truncate the underlying vector to the least length required.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    ///
+    /// let mut s = BitvSet::new();
+    /// s.insert(32183231);
+    /// s.remove(&32183231);
+    ///
+    /// // Internal storage will probably be bigger than necessary
+    /// println!("old capacity: {}", s.capacity());
+    ///
+    /// // Now should be smaller
+    /// s.shrink_to_fit();
+    /// println!("new capacity: {}", s.capacity());
+    /// ```
     #[inline]
-    /// Truncate the underlying vector to the least length required
     pub fn shrink_to_fit(&mut self) {
         let &BitvSet(ref mut bitv) = self;
         // Obtain original length
@@ -723,84 +1153,245 @@ pub fn shrink_to_fit(&mut self) {
         bitv.nbits = trunc_len * uint::BITS;
     }
 
-    /// Union in-place with the specified other bit vector
-    #[inline]
-    pub fn union_with(&mut self, other: &BitvSet) {
-        self.other_op(other, |w1, w2| w1 | w2);
-    }
-
-    /// Intersect in-place with the specified other bit vector
-    #[inline]
-    pub fn intersect_with(&mut self, other: &BitvSet) {
-        self.other_op(other, |w1, w2| w1 & w2);
-    }
-
-    /// Difference in-place with the specified other bit vector
-    #[inline]
-    pub fn difference_with(&mut self, other: &BitvSet) {
-        self.other_op(other, |w1, w2| w1 & !w2);
-    }
-
-    /// Symmetric difference in-place with the specified other bit vector
-    #[inline]
-    pub fn symmetric_difference_with(&mut self, other: &BitvSet) {
-        self.other_op(other, |w1, w2| w1 ^ w2);
-    }
-
-    /// Iterator over each uint stored in the BitvSet
+    /// Iterator over each uint stored in the BitvSet.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let s = BitvSet::from_bitv(bitv::from_bytes([0b01001010]));
+    ///
+    /// // Print 1, 4, 6 in arbitrary order
+    /// for x in s.iter() {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     #[inline]
     pub fn iter<'a>(&'a self) -> BitPositions<'a> {
         BitPositions {set: self, next_idx: 0}
     }
 
-    /// Iterator over each uint stored in the `self` setminus `other`
+    /// Iterator over each uint stored in `self` union `other`.
+    /// See [union_with](#method.union_with) for an efficient in-place version.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000]));
+    ///
+    /// // Print 0, 1, 2, 4 in arbitrary order
+    /// for x in a.union(&b) {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     #[inline]
-    pub fn difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
+    pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
         TwoBitPositions {
             set: self,
             other: other,
-            merge: |w1, w2| w1 & !w2,
+            merge: |w1, w2| w1 w2,
             current_word: 0,
             next_idx: 0
         }
     }
 
-    /// Iterator over each uint stored in the symmetric difference of `self` and `other`
+    /// Iterator over each uint stored in `self` intersect `other`.
+    /// See [intersect_with](#method.intersect_with) for an efficient in-place version.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000]));
+    ///
+    /// // Print 2
+    /// for x in a.intersection(&b) {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     #[inline]
-    pub fn symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
+    pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take<TwoBitPositions<'a>> {
+        let min = cmp::min(self.capacity(), other.capacity());
         TwoBitPositions {
             set: self,
             other: other,
-            merge: |w1, w2| w1 ^ w2,
+            merge: |w1, w2| w1 & w2,
             current_word: 0,
             next_idx: 0
-        }
+        }.take(min)
     }
 
-    /// Iterator over each uint stored in `self` intersect `other`
+    /// Iterator over each uint stored in the `self` setminus `other`.
+    /// See [difference_with](#method.difference_with) for an efficient in-place version.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000]));
+    ///
+    /// // Print 2, 4 in arbitrary order
+    /// for x in a.difference(&b) {
+    ///     println!("{}", x);
+    /// }
+    ///
+    /// // Note that difference is not symmetric,
+    /// // and `b - a` means something else.
+    /// // This prints 0
+    /// for x in b.difference(&a) {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     #[inline]
-    pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take<TwoBitPositions<'a>> {
-        let min = cmp::min(self.capacity(), other.capacity());
+    pub fn difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
         TwoBitPositions {
             set: self,
             other: other,
-            merge: |w1, w2| w1 & w2,
+            merge: |w1, w2| w1 & !w2,
             current_word: 0,
             next_idx: 0
-        }.take(min)
+        }
     }
 
-    /// Iterator over each uint stored in `self` union `other`
+    /// Iterator over each uint stored in the symmetric difference of `self` and `other`.
+    /// See [symmetric_difference_with](#method.symmetric_difference_with) for
+    /// an efficient in-place version.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000]));
+    ///
+    /// // Print 0, 1, 4 in arbitrary order
+    /// for x in a.symmetric_difference(&b) {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     #[inline]
-    pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
+    pub fn symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
         TwoBitPositions {
             set: self,
             other: other,
-            merge: |w1, w2| w1 | w2,
+            merge: |w1, w2| w1 ^ w2,
             current_word: 0,
             next_idx: 0
         }
     }
+
+    /// Union in-place with the specified other bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01101000;
+    /// let b   = 0b10100000;
+    /// let res = 0b11101000;
+    ///
+    /// let mut a = BitvSet::from_bitv(bitv::from_bytes([a]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([b]));
+    ///
+    /// a.union_with(&b);
+    /// assert_eq!(a.unwrap(), bitv::from_bytes([res]));
+    /// ```
+    #[inline]
+    pub fn union_with(&mut self, other: &BitvSet) {
+        self.other_op(other, |w1, w2| w1 | w2);
+    }
+
+    /// Intersect in-place with the specified other bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01101000;
+    /// let b   = 0b10100000;
+    /// let res = 0b00100000;
+    ///
+    /// let mut a = BitvSet::from_bitv(bitv::from_bytes([a]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([b]));
+    ///
+    /// a.intersect_with(&b);
+    /// assert_eq!(a.unwrap(), bitv::from_bytes([res]));
+    /// ```
+    #[inline]
+    pub fn intersect_with(&mut self, other: &BitvSet) {
+        self.other_op(other, |w1, w2| w1 & w2);
+    }
+
+    /// Difference in-place with the specified other bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01101000;
+    /// let b   = 0b10100000;
+    /// let a_b = 0b01001000; // a - b
+    /// let b_a = 0b10000000; // b - a
+    ///
+    /// let mut bva = BitvSet::from_bitv(bitv::from_bytes([a]));
+    /// let bvb = BitvSet::from_bitv(bitv::from_bytes([b]));
+    ///
+    /// bva.difference_with(&bvb);
+    /// assert_eq!(bva.unwrap(), bitv::from_bytes([a_b]));
+    ///
+    /// let bva = BitvSet::from_bitv(bitv::from_bytes([a]));
+    /// let mut bvb = BitvSet::from_bitv(bitv::from_bytes([b]));
+    ///
+    /// bvb.difference_with(&bva);
+    /// assert_eq!(bvb.unwrap(), bitv::from_bytes([b_a]));
+    /// ```
+    #[inline]
+    pub fn difference_with(&mut self, other: &BitvSet) {
+        self.other_op(other, |w1, w2| w1 & !w2);
+    }
+
+    /// Symmetric difference in-place with the specified other bit vector.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::BitvSet;
+    /// use std::collections::bitv;
+    ///
+    /// let a   = 0b01101000;
+    /// let b   = 0b10100000;
+    /// let res = 0b11001000;
+    ///
+    /// let mut a = BitvSet::from_bitv(bitv::from_bytes([a]));
+    /// let b = BitvSet::from_bitv(bitv::from_bytes([b]));
+    ///
+    /// a.symmetric_difference_with(&b);
+    /// assert_eq!(a.unwrap(), bitv::from_bytes([res]));
+    /// ```
+    #[inline]
+    pub fn symmetric_difference_with(&mut self, other: &BitvSet) {
+        self.other_op(other, |w1, w2| w1 ^ w2);
+    }
 }
 
 impl fmt::Show for BitvSet {
@@ -905,11 +1496,13 @@ fn remove(&mut self, value: &uint) -> bool {
     }
 }
 
+/// An iterator for `BitvSet`.
 pub struct BitPositions<'a> {
     set: &'a BitvSet,
     next_idx: uint
 }
 
+/// An iterator combining wo `BitvSet` iterators.
 pub struct TwoBitPositions<'a> {
     set: &'a BitvSet,
     other: &'a BitvSet,
index 1c7e03f70c8896531a6c4b6bea254f6d06faff85..7168af89b59ea36f600068c14b75ee559bd28299 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 /*!
  * Implementation of SipHash 2-4
index d3c0c8856bd47d5b653c7dcff6d418316501d1ff..fba89df1bbc6b2555b9cbb75158d3f9f17866b2c 100644 (file)
@@ -327,33 +327,200 @@ pub trait MutableSet<T>: Set<T> + Mutable {
 
 /// A double-ended sequence that allows querying, insertion and deletion at both
 /// ends.
+///
+/// # Example
+///
+/// With a `Deque` we can simulate a queue efficiently:
+///
+/// ```
+/// use std::collections::{RingBuf, Deque};
+///
+/// let mut queue = RingBuf::new();
+/// queue.push_back(1i);
+/// queue.push_back(2i);
+/// queue.push_back(3i);
+///
+/// // Will print 1, 2, 3
+/// while !queue.is_empty() {
+///     let x = queue.pop_front().unwrap();
+///     println!("{}", x);
+/// }
+/// ```
+///
+/// We can also simulate a stack:
+///
+/// ```
+/// use std::collections::{RingBuf, Deque};
+///
+/// let mut stack = RingBuf::new();
+/// stack.push_front(1i);
+/// stack.push_front(2i);
+/// stack.push_front(3i);
+///
+/// // Will print 3, 2, 1
+/// while !stack.is_empty() {
+///     let x = stack.pop_front().unwrap();
+///     println!("{}", x);
+/// }
+/// ```
+///
+/// And of course we can mix and match:
+///
+/// ```
+/// use std::collections::{DList, Deque};
+///
+/// let mut deque = DList::new();
+///
+/// // Init deque with 1, 2, 3, 4
+/// deque.push_front(2i);
+/// deque.push_front(1i);
+/// deque.push_back(3i);
+/// deque.push_back(4i);
+///
+/// // Will print (1, 4) and (2, 3)
+/// while !deque.is_empty() {
+///     let f = deque.pop_front().unwrap();
+///     let b = deque.pop_back().unwrap();
+///     println!("{}", (f, b));
+/// }
+/// ```
 pub trait Deque<T> : Mutable {
-    /// Provide a reference to the front element, or None if the sequence is
-    /// empty
+    /// Provide a reference to the front element, or `None` if the sequence is
+    /// empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{RingBuf, Deque};
+    ///
+    /// let mut d = RingBuf::new();
+    /// assert_eq!(d.front(), None);
+    ///
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    /// assert_eq!(d.front(), Some(&1i));
+    /// ```
     fn front<'a>(&'a self) -> Option<&'a T>;
 
-    /// Provide a mutable reference to the front element, or None if the
-    /// sequence is empty
+    /// Provide a mutable reference to the front element, or `None` if the
+    /// sequence is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{RingBuf, Deque};
+    ///
+    /// let mut d = RingBuf::new();
+    /// assert_eq!(d.front_mut(), None);
+    ///
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    /// match d.front_mut() {
+    ///     Some(x) => *x = 9i,
+    ///     None => (),
+    /// }
+    /// assert_eq!(d.front(), Some(&9i));
+    /// ```
     fn front_mut<'a>(&'a mut self) -> Option<&'a mut T>;
 
-    /// Provide a reference to the back element, or None if the sequence is
-    /// empty
+    /// Provide a reference to the back element, or `None` if the sequence is
+    /// empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut d = DList::new();
+    /// assert_eq!(d.back(), None);
+    ///
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    /// assert_eq!(d.back(), Some(&2i));
+    /// ```
     fn back<'a>(&'a self) -> Option<&'a T>;
 
-    /// Provide a mutable reference to the back element, or None if the sequence
-    /// is empty
+    /// Provide a mutable reference to the back element, or `None` if the sequence
+    /// is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut d = DList::new();
+    /// assert_eq!(d.back(), None);
+    ///
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    /// match d.back_mut() {
+    ///     Some(x) => *x = 9i,
+    ///     None => (),
+    /// }
+    /// assert_eq!(d.back(), Some(&9i));
+    /// ```
     fn back_mut<'a>(&'a mut self) -> Option<&'a mut T>;
 
-    /// Insert an element first in the sequence
+    /// Insert an element first in the sequence.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut d = DList::new();
+    /// d.push_front(1i);
+    /// d.push_front(2i);
+    /// assert_eq!(d.front(), Some(&2i));
+    /// ```
     fn push_front(&mut self, elt: T);
 
-    /// Insert an element last in the sequence
+    /// Insert an element last in the sequence.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{DList, Deque};
+    ///
+    /// let mut d = DList::new();
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    /// assert_eq!(d.front(), Some(&1i));
+    /// ```
     fn push_back(&mut self, elt: T);
 
-    /// Remove the last element and return it, or None if the sequence is empty
+    /// Remove the last element and return it, or `None` if the sequence is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{RingBuf, Deque};
+    ///
+    /// let mut d = RingBuf::new();
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    ///
+    /// assert_eq!(d.pop_back(), Some(2i));
+    /// assert_eq!(d.pop_back(), Some(1i));
+    /// assert_eq!(d.pop_back(), None);
+    /// ```
     fn pop_back(&mut self) -> Option<T>;
 
-    /// Remove the first element and return it, or None if the sequence is empty
+    /// Remove the first element and return it, or `None` if the sequence is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::collections::{RingBuf, Deque};
+    ///
+    /// let mut d = RingBuf::new();
+    /// d.push_back(1i);
+    /// d.push_back(2i);
+    ///
+    /// assert_eq!(d.pop_front(), Some(1i));
+    /// assert_eq!(d.pop_front(), Some(2i));
+    /// assert_eq!(d.pop_front(), None);
+    /// ```
     fn pop_front(&mut self) -> Option<T>;
 }
 
index 1c5aa8a323bab8cdaca429e08dfb3d35cd7766d1..6c3c8437e255a6c8845700a3c522c3163cfc77c3 100644 (file)
@@ -155,7 +155,7 @@ fn connect_vec(&self, sep: &T) -> Vec<T> {
 /// a sequence of all possible permutations for an indexed sequence of
 /// elements. Each permutation is only a single swap apart.
 ///
-/// The Steinhaus–Johnson–Trotter algorithm is used.
+/// The Steinhaus-Johnson-Trotter algorithm is used.
 ///
 /// Generates even and odd permutations alternately.
 ///
index 1e29679f8a79ec61c363c6f5ef68e846927ec5e6..48bc492e25ce4d591ed6af22fa8d52ba6ad7d2c9 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 /*!
 
index 5450f2d7c31a3778b63ca8947341e55f96f62311..b19bef685901fdea57a3e136bcade71c34e18646 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! An owned, growable string that enforces that its contents are valid UTF-8.
 
@@ -856,8 +858,7 @@ fn from_utf8_lossy_100_ascii(b: &mut Bencher) {
 
     #[bench]
     fn from_utf8_lossy_100_multibyte(b: &mut Bencher) {
-        let s = "ð\90Œ€ð\90Œ–ð\90Œ‹ð\90Œ„ð\90Œ‘ð\90Œ‰à¸›à¸£Ø¯ÙˆÙ„Ø©\
-            Ø§Ù„كويتทศไทย中å\8dŽð\90\8d…ð\90Œ¿ð\90Œ»ð\90\8d†ð\90Œ¹ð\90Œ»ð\90Œ°".as_bytes();
+        let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes();
         assert_eq!(100, s.len());
         b.iter(|| {
             let _ = String::from_utf8_lossy(s);
index 96228531ae54f05446cb5777b4dc6536d98f8200..751775888b7590fee4f9ed3edec0d0074dd38035 100644 (file)
 /// The `vec!` macro is provided to make initialization more convenient:
 ///
 /// ```rust
-/// let mut vec = vec!(1i, 2i, 3i);
+/// let mut vec = vec![1i, 2i, 3i];
 /// vec.push(4);
-/// assert_eq!(vec, vec!(1, 2, 3, 4));
+/// assert_eq!(vec, vec![1, 2, 3, 4]);
 /// ```
+///
+/// # Capacity and reallocation
+///
+/// The capacity of a vector is the amount of space allocated for any future
+/// elements that will be added onto the vector. This is not to be confused
+/// with the *length* of a vector, which specifies the number of actual
+/// elements within the vector. If a vector's length exceeds its capacity,
+/// its capacity will automatically be increased, but its elements will
+/// have to be reallocated.
+///
+/// For example, a vector with capacity 10 and length 0 would be an empty
+/// vector with space for 10 more elements. Pushing 10 or fewer elements onto
+/// the vector will not change its capacity or cause reallocation to occur.
+/// However, if the vector's length is increased to 11, it will have to
+/// reallocate, which can be slow. For this reason, it is recommended
+/// to use `Vec::with_capacity` whenever possible to specify how big the vector
+/// is expected to get.
 #[unsafe_no_drop_flag]
 pub struct Vec<T> {
     len: uint,
@@ -87,11 +104,28 @@ pub fn new() -> Vec<T> {
     /// The vector will be able to hold exactly `capacity` elements without
     /// reallocating. If `capacity` is 0, the vector will not allocate.
     ///
+    /// It is important to note that this function does not specify the
+    /// *length* of the returned vector, but only the *capacity*. (For an
+    /// explanation of the difference between length and capacity, see
+    /// the main `Vec` docs above, 'Capacity and reallocation'.) To create
+    /// a vector of a given length, use `Vec::from_elem` or `Vec::from_fn`.
+    ///
     /// # Example
     ///
     /// ```rust
     /// # use std::vec::Vec;
-    /// let vec: Vec<int> = Vec::with_capacity(10);
+    /// let mut vec: Vec<int> = Vec::with_capacity(10);
+    ///
+    /// // The vector contains no items, even though it has capacity for more
+    /// assert_eq!(vec.len(), 0);
+    ///
+    /// // These are all done without reallocating...
+    /// for i in range(0i, 10) {
+    ///     vec.push(i);
+    /// }
+    ///
+    /// // ...but this may make the vector reallocate
+    /// vec.push(11);
     /// ```
     #[inline]
     pub fn with_capacity(capacity: uint) -> Vec<T> {
index 855bccb07a7418305a90f1e19d83187a1e13af6b..6ba0f7c3a157543d3b4968b5476bdbed642ae4d9 100644 (file)
@@ -1962,7 +1962,19 @@ pub struct Range<A> {
     one: A
 }
 
-/// Return an iterator over the range [start, stop)
+/// Returns an iterator over the given range [start, stop) (that is, starting
+/// at start (inclusive), and ending at stop (exclusive)).
+///
+/// # Example
+///
+/// ```rust
+/// let array = [0, 1, 2, 3, 4];
+///
+/// for i in range(0, 5u) {
+///     println!("{}", i);
+///     assert_eq!(i,  array[i]);
+/// }
+/// ```
 #[inline]
 pub fn range<A: Add<A, A> + PartialOrd + Clone + One>(start: A, stop: A) -> Range<A> {
     Range{state: start, stop: stop, one: One::one()}
index 3230873883e19113bcf78fc8e4b9a785080fa7c7..3ffc1d5e11c7371dfe41667fe788a11900ad2e4b 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! Numeric traits and functions for generic mathematics
 
index c6aff9c8bdac8c58147e17131ea3a491080cca38..37af64d74d414334b82129995f1d9c0c43ac6222 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! String manipulation
 //!
index 51d13535caf303758b34fca2df3212f62714cace..ebc6e9862288090408db96e27825f8e65aec56a2 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 use core::char::{escape_unicode, escape_default};
 
index bf39fd566e52d200ea2ff367ca4796e7312f1575..96b9a6a13923cf94e14baec68a516181fffaa799 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15677
 
 //! Simple getopt alternative.
 //!
index 3c93a795071a6719831719aa4007036a7119d08e..f55a1ca62f72f06ef7e91f37fb0f92427c7b7e6e 100644 (file)
@@ -548,7 +548,7 @@ struct Edge {
         from: uint, to: uint, label: &'static str
     }
 
-    fn Edge(from: uint, to: uint, label: &'static str) -> Edge {
+    fn edge(from: uint, to: uint, label: &'static str) -> Edge {
         Edge { from: from, to: to, label: label }
     }
 
@@ -723,7 +723,7 @@ fn single_node() {
     fn single_edge() {
         let labels : Trivial = UnlabelledNodes(2);
         let result = test_input(LabelledGraph::new("single_edge", labels,
-                                                   vec!(Edge(0, 1, "E"))));
+                                                   vec!(edge(0, 1, "E"))));
         assert_eq!(result.unwrap().as_slice(),
 r#"digraph single_edge {
     N0[label="N0"];
@@ -737,7 +737,7 @@ fn single_edge() {
     fn single_cyclic_node() {
         let labels : Trivial = UnlabelledNodes(1);
         let r = test_input(LabelledGraph::new("single_cyclic_node", labels,
-                                              vec!(Edge(0, 0, "E"))));
+                                              vec!(edge(0, 0, "E"))));
         assert_eq!(r.unwrap().as_slice(),
 r#"digraph single_cyclic_node {
     N0[label="N0"];
@@ -751,8 +751,8 @@ fn hasse_diagram() {
         let labels = AllNodesLabelled(vec!("{x,y}", "{x}", "{y}", "{}"));
         let r = test_input(LabelledGraph::new(
             "hasse_diagram", labels,
-            vec!(Edge(0, 1, ""), Edge(0, 2, ""),
-                 Edge(1, 3, ""), Edge(2, 3, ""))));
+            vec!(edge(0, 1, ""), edge(0, 2, ""),
+                 edge(1, 3, ""), edge(2, 3, ""))));
         assert_eq!(r.unwrap().as_slice(),
 r#"digraph hasse_diagram {
     N0[label="{x,y}"];
@@ -785,8 +785,8 @@ fn left_aligned_text() {
 
         let g = LabelledGraphWithEscStrs::new(
             "syntax_tree", labels,
-            vec!(Edge(0, 1, "then"), Edge(0, 2, "else"),
-                 Edge(1, 3, ";"),    Edge(2, 3, ";"   )));
+            vec!(edge(0, 1, "then"), edge(0, 2, "else"),
+                 edge(1, 3, ";"),    edge(2, 3, ";"   )));
 
         render(&g, &mut writer).unwrap();
         let mut r = BufReader::new(writer.get_ref());
index eddf17b34b9ff070075b53a44f73bd54fc20c150..4cce430d88a8d3522e1e75e776a64ab1a29cd97b 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // FIXME: this file probably shouldn't exist
+// ignore-lexer-test FIXME #15677
 
 #![macro_escape]
 
index 72cf5e785fb93a52426e2143d04b0a3ea1862462..e98fe1e20b19e7be92cf6a9266e5103abf964fb7 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-lexer-test FIXME #15877
+
 //! Windows specific console TTY implementation
 //!
 //! This module contains the implementation of a Windows specific console TTY.
index a9f24e1a9ecc769d3fc8932a5dde58687d749c3b..7b6e94eaa92092ab5af560e8040bce1f56ea2778 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! The Gamma and derived distributions.
 
index 1bb7f605e5474878d8a4837e4f18eb2d1fecebbd..fae3e5986806d6ce0431f83257c08e73768c2a65 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! This crate provides a native implementation of regular expressions that is
 //! heavily based on RE2 both in syntax and in implementation. Notably,
index 251ab10ad34e9d47c2950357647522ccf340b238..48065992bb050f525dd7133f54402f23d8546f5c 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
+// ignore-lexer-test FIXME #15679
 
 use regex::{Regex, NoExpand};
 
index 7163dfa3b16abf6b27035913d63e1eebf60b941c..07539a11113f5aaeeaf2b33833bb1581d85567bc 100644 (file)
@@ -34,6 +34,7 @@
 use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
 use syntax::parse::token;
 use syntax::print::pprust;
+use syntax::fold::Folder;
 
 use rustc::plugin::Registry;
 
@@ -615,7 +616,7 @@ fn vec_expr<T, It: Iterator<T>>(&self, xs: It,
 /// Otherwise, logs an error with cx.span_err and returns None.
 fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
     let mut parser = cx.new_parser_from_tts(tts);
-    let entry = cx.expand_expr(parser.parse_expr());
+    let entry = cx.expander().fold_expr(parser.parse_expr());
     let regex = match entry.node {
         ast::ExprLit(lit) => {
             match lit.node {
index cb27596c98c6b1a92159b30e24cda00239f353ce..c7295125f42f7504de4c1c22546b748058b9f197 100644 (file)
 //! the system libc library.
 
 #![crate_name = "rlibc"]
+#![experimental]
 #![license = "MIT/ASL2"]
 #![crate_type = "rlib"]
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/master/")]
-#![feature(intrinsics)]
 
+#![feature(intrinsics, phase)]
 #![no_std]
-#![experimental]
 
 // This library defines the builtin functions, so it would be a shame for
 // LLVM to optimize these function calls to themselves!
 #![no_builtins]
 
-#[cfg(test)] extern crate std;
 #[cfg(test)] extern crate native;
+#[cfg(test)] extern crate test;
+#[cfg(test)] extern crate debug;
+
+#[cfg(test)] #[phase(plugin, link)] extern crate std;
+#[cfg(test)] #[phase(plugin, link)] extern crate core;
 
 // Require the offset intrinsics for LLVM to properly optimize the
 // implementations below. If pointer arithmetic is done through integers the
         let a = *offset(s1, i as int);
         let b = *offset(s2, i as int);
         if a != b {
-            return (a - b) as i32
+            return a as i32 - b as i32
         }
         i += 1;
     }
     return 0;
 }
 
-#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
+#[cfg(test)]
+mod test {
+    use core::option::{Some, None};
+    use core::iter::Iterator;
+    use core::collections::Collection;
+    use core::str::StrSlice;
+    use core::slice::{MutableVector, ImmutableVector};
+
+    use super::{memcmp, memset, memcpy, memmove};
+
+    #[test]
+    fn memcmp_single_byte_pointers() {
+        unsafe {
+            assert_eq!(memcmp(&0xFAu8, &0xFAu8, 1), 0x00);
+            assert!(memcmp(&0xEFu8, &0xFEu8, 1) < 0x00);
+        }
+    }
+
+    #[test]
+    fn memcmp_strings() {
+        {
+            let (x, z) = ("Hello!", "Good Bye.");
+            let l = x.len();
+            unsafe {
+                assert_eq!(memcmp(x.as_ptr(), x.as_ptr(), l), 0);
+                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) > 0);
+                assert!(memcmp(z.as_ptr(), x.as_ptr(), l) < 0);
+            }
+        }
+        {
+            let (x, z) = ("hey!", "hey.");
+            let l = x.len();
+            unsafe {
+                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) < 0);
+            }
+        }
+    }
+
+    #[test]
+    fn memset_single_byte_pointers() {
+        let mut x: u8 = 0xFF;
+        unsafe {
+            memset(&mut x, 0xAA, 1);
+            assert_eq!(x, 0xAA);
+            memset(&mut x, 0x00, 1);
+            assert_eq!(x, 0x00);
+            x = 0x01;
+            memset(&mut x, 0x12, 0);
+            assert_eq!(x, 0x01);
+        }
+    }
+
+    #[test]
+    fn memset_array() {
+        let mut buffer = [b'X', .. 100];
+        unsafe {
+            memset(buffer.as_mut_ptr(), b'#' as i32, buffer.len());
+        }
+        for byte in buffer.iter() { assert_eq!(*byte, b'#'); }
+    }
+
+    #[test]
+    fn memcpy_and_memcmp_arrays() {
+        let (src, mut dst) = ([b'X', .. 100], [b'Y', .. 100]);
+        unsafe {
+            assert!(memcmp(src.as_ptr(), dst.as_ptr(), 100) != 0);
+            let _ = memcpy(dst.as_mut_ptr(), src.as_ptr(), 100);
+            assert_eq!(memcmp(src.as_ptr(), dst.as_ptr(), 100), 0);
+        }
+    }
+
+    #[test]
+    fn memmove_overlapping() {
+        {
+            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
+            unsafe {
+                memmove(&mut buffer[4], &buffer[0], 6);
+                let mut i = 0;
+                for byte in b"0123012345".iter() {
+                    assert_eq!(buffer[i], *byte);
+                    i += 1;
+                }
+            }
+        }
+        {
+            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
+            unsafe {
+                memmove(&mut buffer[0], &buffer[4], 6);
+                let mut i = 0;
+                for byte in b"4567896789".iter() {
+                    assert_eq!(buffer[i], *byte);
+                    i += 1;
+                }
+            }
+        }
+    }
+}
index ee611293475f9011702f7196c5482d244e3b962a..dd951d963e0d7cfcfd35d0c8038e83e4a26dd65e 100644 (file)
@@ -97,6 +97,10 @@ pub struct Options {
     pub color: ColorConfig,
     pub externs: HashMap<String, Vec<String>>,
     pub crate_name: Option<String>,
+    /// An optional name to use as the crate for std during std injection,
+    /// written `extern crate std = "name"`. Default to "std". Used by
+    /// out-of-tree drivers.
+    pub alt_std_name: Option<String>
 }
 
 /// Some reasonable defaults
@@ -124,6 +128,7 @@ pub fn basic_options() -> Options {
         color: Auto,
         externs: HashMap::new(),
         crate_name: None,
+        alt_std_name: None,
     }
 }
 
@@ -577,7 +582,7 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
             always = always colorize output;
             never  = never colorize output", "auto|always|never"),
         optmulti("", "extern", "Specify where an external rust library is located",
-                 "PATH"),
+                 "NAME=PATH"),
     )
 }
 
@@ -593,24 +598,10 @@ fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
 }
 
 pub fn build_session_options(matches: &getopts::Matches) -> Options {
-    let mut crate_types: Vec<CrateType> = Vec::new();
+
     let unparsed_crate_types = matches.opt_strs("crate-type");
-    for unparsed_crate_type in unparsed_crate_types.iter() {
-        for part in unparsed_crate_type.as_slice().split(',') {
-            let new_part = match part {
-                "lib"       => default_lib_output(),
-                "rlib"      => CrateTypeRlib,
-                "staticlib" => CrateTypeStaticlib,
-                "dylib"     => CrateTypeDylib,
-                "bin"       => CrateTypeExecutable,
-                _ => {
-                    early_error(format!("unknown crate type: `{}`",
-                                        part).as_slice())
-                }
-            };
-            crate_types.push(new_part)
-        }
-    }
+    let crate_types = parse_crate_types_from_list(unparsed_crate_types)
+        .unwrap_or_else(|e| early_error(e.as_slice()));
 
     let parse_only = matches.opt_present("parse-only");
     let no_trans = matches.opt_present("no-trans");
@@ -801,9 +792,33 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         color: color,
         externs: externs,
         crate_name: crate_name,
+        alt_std_name: None
     }
 }
 
+pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
+
+    let mut crate_types: Vec<CrateType> = Vec::new();
+    for unparsed_crate_type in list_list.iter() {
+        for part in unparsed_crate_type.as_slice().split(',') {
+            let new_part = match part {
+                "lib"       => default_lib_output(),
+                "rlib"      => CrateTypeRlib,
+                "staticlib" => CrateTypeStaticlib,
+                "dylib"     => CrateTypeDylib,
+                "bin"       => CrateTypeExecutable,
+                _ => {
+                    return Err(format!("unknown crate type: `{}`",
+                                       part));
+                }
+            };
+            crate_types.push(new_part)
+        }
+    }
+
+    return Ok(crate_types);
+}
+
 impl fmt::Show for CrateType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
index 81ace4d015c8576101d566fb499694e4856eb5f7..9796aab51fb6b26b125bdc3fdd3524eabe31b2ed 100644 (file)
@@ -69,7 +69,8 @@ pub fn compile_input(sess: Session,
                      cfg: ast::CrateConfig,
                      input: &Input,
                      outdir: &Option<Path>,
-                     output: &Option<Path>) {
+                     output: &Option<Path>,
+                     addl_plugins: Option<Plugins>) {
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
@@ -85,7 +86,8 @@ pub fn compile_input(sess: Session,
             let id = link::find_crate_name(Some(&sess), krate.attrs.as_slice(),
                                            input);
             let (expanded_crate, ast_map)
-                = match phase_2_configure_and_expand(&sess, krate, id.as_slice()) {
+                = match phase_2_configure_and_expand(&sess, krate, id.as_slice(),
+                                                     addl_plugins) {
                     None => return,
                     Some(p) => p,
                 };
@@ -179,6 +181,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
 // modified
 
 /// Run the "early phases" of the compiler: initial `cfg` processing,
+/// loading compiler plugins (including those from `addl_plugins`),
 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
 /// harness if one is to be provided and injection of a dependency on the
 /// standard library and prelude.
@@ -186,7 +189,8 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
 /// Returns `None` if we're aborting after handling -W help.
 pub fn phase_2_configure_and_expand(sess: &Session,
                                     mut krate: ast::Crate,
-                                    crate_name: &str)
+                                    crate_name: &str,
+                                    addl_plugins: Option<Plugins>)
                                     -> Option<(ast::Crate, syntax::ast_map::Map)> {
     let time_passes = sess.time_passes();
 
@@ -212,9 +216,10 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     krate = time(time_passes, "configuration 1", krate, |krate|
                  front::config::strip_unconfigured_items(krate));
 
+    let mut addl_plugins = Some(addl_plugins);
     let Plugins { macros, registrars }
         = time(time_passes, "plugin loading", (), |_|
-               plugin::load::load_plugins(sess, &krate));
+               plugin::load::load_plugins(sess, &krate, addl_plugins.take_unwrap()));
 
     let mut registry = Registry::new(&krate);
 
@@ -697,7 +702,7 @@ pub fn pretty_print_input(sess: Session,
         PpmExpanded | PpmExpandedIdentified | PpmTyped | PpmFlowGraph(_) => {
             let (krate, ast_map)
                 = match phase_2_configure_and_expand(&sess, krate,
-                                                     id.as_slice()) {
+                                                     id.as_slice(), None) {
                     None => return,
                     Some(p) => p,
                 };
index e433c3df8644c2713e179d200c17d90960ca48ac..a5df63a9e23fa813400889f76c807bf7a5a19ebe 100644 (file)
@@ -124,7 +124,7 @@ fn run_compiler(args: &[String]) {
         return;
     }
 
-    driver::compile_input(sess, cfg, &input, &odir, &ofile);
+    driver::compile_input(sess, cfg, &input, &odir, &ofile, None);
 }
 
 /// Prints version information and returns None on success or an error
@@ -418,7 +418,7 @@ pub fn list_metadata(sess: &Session, path: &Path,
 ///
 /// The diagnostic emitter yielded to the procedure should be used for reporting
 /// errors of the compiler.
-fn monitor(f: proc():Send) {
+pub fn monitor(f: proc():Send) {
     // FIXME: This is a hack for newsched since it doesn't support split stacks.
     // rustc needs a lot of stack! When optimizations are disabled, it needs
     // even *more* stack than usual as well.
index 351c9a6b771672c6506c4c95f04d1419a8c71b87..940112325fdf42d61040a431d81518d573a2edca 100644 (file)
@@ -60,9 +60,16 @@ struct StandardLibraryInjector<'a> {
 
 impl<'a> fold::Folder for StandardLibraryInjector<'a> {
     fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+
+        // The name to use in `extern crate std = "name";`
+        let actual_crate_name = match self.sess.opts.alt_std_name {
+            Some(ref s) => token::intern_and_get_ident(s.as_slice()),
+            None => token::intern_and_get_ident("std"),
+        };
+
         let mut vis = vec!(ast::ViewItem {
             node: ast::ViewItemExternCrate(token::str_to_ident("std"),
-                                           None,
+                                           Some((actual_crate_name, ast::CookedStr)),
                                            ast::DUMMY_NODE_ID),
             attrs: vec!(
                 attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
index 0860d111a9ef04a2f254bbf2de4b615856651cd2..08907f6c0ed5d8394a1004f9eac95091e3023ef6 100644 (file)
@@ -16,9 +16,9 @@
 use driver::session::Session;
 use front::config;
 
-use std::cell::RefCell;
 use std::gc::{Gc, GC};
 use std::slice;
+use std::mem;
 use std::vec;
 use syntax::ast_util::*;
 use syntax::attr::AttrMetaMethods;
@@ -26,6 +26,7 @@
 use syntax::codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
 use syntax::codemap;
 use syntax::ext::base::ExtCtxt;
+use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
 use syntax::fold::Folder;
 use syntax::fold;
@@ -46,9 +47,11 @@ struct Test {
 
 struct TestCtxt<'a> {
     sess: &'a Session,
-    path: RefCell<Vec<ast::Ident>>,
+    path: Vec<ast::Ident>,
+    reexports: Vec<Vec<ast::Ident>>,
     ext_cx: ExtCtxt<'a>,
-    testfns: RefCell<Vec<Test> >,
+    testfns: Vec<Test>,
+    reexport_mod_ident: ast::Ident,
     is_test_crate: bool,
     config: ast::CrateConfig,
 }
@@ -86,9 +89,9 @@ fn fold_crate(&mut self, c: ast::Crate) -> ast::Crate {
     }
 
     fn fold_item(&mut self, i: Gc<ast::Item>) -> SmallVector<Gc<ast::Item>> {
-        self.cx.path.borrow_mut().push(i.ident);
+        self.cx.path.push(i.ident);
         debug!("current path: {}",
-               ast_util::path_name_i(self.cx.path.borrow().as_slice()));
+               ast_util::path_name_i(self.cx.path.as_slice()));
 
         if is_test_fn(&self.cx, i) || is_bench_fn(&self.cx, i) {
             match i.node {
@@ -102,31 +105,41 @@ fn fold_item(&mut self, i: Gc<ast::Item>) -> SmallVector<Gc<ast::Item>> {
                     debug!("this is a test function");
                     let test = Test {
                         span: i.span,
-                        path: self.cx.path.borrow().clone(),
+                        path: self.cx.path.clone(),
                         bench: is_bench_fn(&self.cx, i),
                         ignore: is_ignored(&self.cx, i),
                         should_fail: should_fail(i)
                     };
-                    self.cx.testfns.borrow_mut().push(test);
+                    self.cx.testfns.push(test);
+                    self.cx.reexports.push(self.cx.path.clone());
                     // debug!("have {} test/bench functions",
                     //        cx.testfns.len());
                 }
             }
         }
 
-        let res = fold::noop_fold_item(&*i, self);
-        self.cx.path.borrow_mut().pop();
+        // We don't want to recurse into anything other than mods, since
+        // mods or tests inside of functions will break things
+        let res = match i.node {
+            ast::ItemMod(..) => fold::noop_fold_item(&*i, self),
+            _ => SmallVector::one(i),
+        };
+        self.cx.path.pop();
         res
     }
 
     fn fold_mod(&mut self, m: &ast::Mod) -> ast::Mod {
+        let reexports = mem::replace(&mut self.cx.reexports, Vec::new());
+        let mut mod_folded = fold::noop_fold_mod(m, self);
+        let reexports = mem::replace(&mut self.cx.reexports, reexports);
+
         // Remove any #[main] from the AST so it doesn't clash with
         // the one we're going to add. Only if compiling an executable.
 
         fn nomain(item: Gc<ast::Item>) -> Gc<ast::Item> {
             box(GC) ast::Item {
                 attrs: item.attrs.iter().filter_map(|attr| {
-                    if !attr.name().equiv(&("main")) {
+                    if !attr.check_name("main") {
                         Some(*attr)
                     } else {
                         None
@@ -136,18 +149,39 @@ fn nomain(item: Gc<ast::Item>) -> Gc<ast::Item> {
             }
         }
 
-        let mod_nomain = ast::Mod {
-            inner: m.inner,
-            view_items: m.view_items.clone(),
-            items: m.items.iter().map(|i| nomain(*i)).collect(),
-        };
+        for i in mod_folded.items.mut_iter() {
+            *i = nomain(*i);
+        }
+        if !reexports.is_empty() {
+            mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports));
+            self.cx.reexports.push(self.cx.path.clone());
+        }
+
+        mod_folded
+    }
+}
 
-        fold::noop_fold_mod(&mod_nomain, self)
+fn mk_reexport_mod(cx: &mut TestCtxt, reexports: Vec<Vec<ast::Ident>>)
+                   -> Gc<ast::Item> {
+    let view_items = reexports.move_iter().map(|r| {
+        cx.ext_cx.view_use_simple(DUMMY_SP, ast::Public, cx.ext_cx.path(DUMMY_SP, r))
+    }).collect();
+    let reexport_mod = ast::Mod {
+        inner: DUMMY_SP,
+        view_items: view_items,
+        items: Vec::new(),
+    };
+    box(GC) ast::Item {
+        ident: cx.reexport_mod_ident.clone(),
+        attrs: Vec::new(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemMod(reexport_mod),
+        vis: ast::Public,
+        span: DUMMY_SP,
     }
 }
 
-fn generate_test_harness(sess: &Session, krate: ast::Crate)
-                         -> ast::Crate {
+fn generate_test_harness(sess: &Session, krate: ast::Crate) -> ast::Crate {
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(),
@@ -155,8 +189,10 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate)
                                  deriving_hash_type_parameter: false,
                                  crate_name: "test".to_string(),
                              }),
-        path: RefCell::new(Vec::new()),
-        testfns: RefCell::new(Vec::new()),
+        path: Vec::new(),
+        reexports: Vec::new(),
+        testfns: Vec::new(),
+        reexport_mod_ident: token::str_to_ident("__test_reexports"),
         is_test_crate: is_test_crate(&krate),
         config: krate.config.clone(),
     };
@@ -171,7 +207,7 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate)
     });
 
     let mut fold = TestHarnessGenerator {
-        cx: cx
+        cx: cx,
     };
     let res = fold.fold_crate(krate);
     fold.cx.ext_cx.bt_pop();
@@ -275,7 +311,6 @@ fn add_test_module(cx: &TestCtxt, m: &ast::Mod) -> ast::Mod {
 We're going to be building a module that looks more or less like:
 
 mod __test {
-  #![!resolve_unexported]
   extern crate test (name = "test", vers = "...");
   fn main() {
     test::test_main_static(::os::args().as_slice(), tests)
@@ -332,15 +367,9 @@ pub fn main() {
     };
     let item_ = ast::ItemMod(testmod);
 
-    // This attribute tells resolve to let us call unexported functions
-    let resolve_unexported_str = InternedString::new("!resolve_unexported");
-    let resolve_unexported_attr =
-        attr::mk_attr_inner(attr::mk_attr_id(),
-                            attr::mk_word_item(resolve_unexported_str));
-
     let item = ast::Item {
         ident: token::str_to_ident("__test"),
-        attrs: vec!(resolve_unexported_attr),
+        attrs: Vec::new(),
         id: ast::DUMMY_NODE_ID,
         node: item_,
         vis: ast::Public,
@@ -368,18 +397,6 @@ fn path_node(ids: Vec<ast::Ident> ) -> ast::Path {
     }
 }
 
-fn path_node_global(ids: Vec<ast::Ident> ) -> ast::Path {
-    ast::Path {
-        span: DUMMY_SP,
-        global: true,
-        segments: ids.move_iter().map(|identifier| ast::PathSegment {
-            identifier: identifier,
-            lifetimes: Vec::new(),
-            types: OwnedSlice::empty(),
-        }).collect()
-    }
-}
-
 fn mk_tests(cx: &TestCtxt) -> Gc<ast::Item> {
     // The vector of test_descs for this crate
     let test_descs = mk_test_descs(cx);
@@ -399,13 +416,13 @@ fn is_test_crate(krate: &ast::Crate) -> bool {
 }
 
 fn mk_test_descs(cx: &TestCtxt) -> Gc<ast::Expr> {
-    debug!("building test vector from {} tests", cx.testfns.borrow().len());
+    debug!("building test vector from {} tests", cx.testfns.len());
 
     box(GC) ast::Expr {
         id: ast::DUMMY_NODE_ID,
         node: ast::ExprVstore(box(GC) ast::Expr {
             id: ast::DUMMY_NODE_ID,
-            node: ast::ExprVec(cx.testfns.borrow().iter().map(|test| {
+            node: ast::ExprVec(cx.testfns.iter().map(|test| {
                 mk_test_desc_and_fn_rec(cx, test)
             }).collect()),
             span: DUMMY_SP,
@@ -431,7 +448,12 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> Gc<ast::Expr> {
           span: span
     };
 
-    let fn_path = path_node_global(path);
+    let mut visible_path = Vec::new();
+    for ident in path.move_iter() {
+        visible_path.push(cx.reexport_mod_ident.clone());
+        visible_path.push(ident);
+    }
+    let fn_path = cx.ext_cx.path_global(DUMMY_SP, visible_path);
 
     let fn_expr = box(GC) ast::Expr {
         id: ast::DUMMY_NODE_ID,
index 439455ff3d15ce3291c07acd9955b1fd852266bd..7997af1ee5e11980e971a569c5b4548d8db70260 100644 (file)
@@ -1618,8 +1618,8 @@ fn encode_macro_defs(ecx: &EncodeContext,
                      krate: &Crate,
                      ebml_w: &mut Encoder) {
     ebml_w.start_tag(tag_exported_macros);
-    for span in krate.exported_macros.iter() {
-        encode_macro_def(ecx, ebml_w, span);
+    for item in krate.exported_macros.iter() {
+        encode_macro_def(ecx, ebml_w, &item.span);
     }
     ebml_w.end_tag();
 }
index bad6a288294f4c25532f080b9aed5c8e670f9986..62b5299f8fbc8619cb0d02319c41f878d8eecc21 100644 (file)
@@ -27,7 +27,6 @@
 use syntax::ast;
 use syntax::ast_map;
 use syntax::ast_util::{is_local, local_def, PostExpansionMethod};
-use syntax::attr;
 use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::owned_slice::OwnedSlice;
@@ -326,7 +325,7 @@ fn visit_item(&mut self, item: &ast::Item, _: ()) {
     }
 
     fn visit_foreign_item(&mut self, a: &ast::ForeignItem, _: ()) {
-        if self.prev_exported && a.vis == ast::Public {
+        if (self.prev_exported && a.vis == ast::Public) || self.reexports.contains(&a.id) {
             self.exported_items.insert(a.id);
         }
     }
@@ -786,12 +785,6 @@ fn check_method(&mut self, span: Span, origin: MethodOrigin,
 
 impl<'a> Visitor<()> for PrivacyVisitor<'a> {
     fn visit_item(&mut self, item: &ast::Item, _: ()) {
-        // Do not check privacy inside items with the resolve_unexported
-        // attribute. This is used for the test runner.
-        if attr::contains_name(item.attrs.as_slice(), "!resolve_unexported") {
-            return;
-        }
-
         let orig_curitem = replace(&mut self.curitem, item.id);
         visit::walk_item(self, item, ());
         self.curitem = orig_curitem;
index aeb171c068a85016a01d2ecc5f799f4a24f6aa9b..7ba49f5a2b90df532ea12ba2e95c52b336cef272 100644 (file)
 use middle::trans::adt;
 use middle::trans::base::*;
 use middle::trans::build::*;
+use middle::trans::build;
 use middle::trans::callee;
 use middle::trans::cleanup;
 use middle::trans::cleanup::CleanupMethods;
 use middle::trans::common::*;
 use middle::trans::consts;
-use middle::trans::controlflow;
 use middle::trans::datum::*;
 use middle::trans::expr::Dest;
 use middle::trans::expr;
 
 use std;
 use std::collections::HashMap;
-use std::cell::Cell;
 use std::rc::Rc;
 use std::gc::{Gc};
 use syntax::ast;
 use syntax::ast::Ident;
 use syntax::codemap::Span;
 use syntax::fold::Folder;
-use syntax::parse::token::InternedString;
 
 #[deriving(PartialEq)]
 pub enum VecLenOpt {
@@ -301,20 +299,6 @@ fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
     }
 }
 
-fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
-    let ccx = bcx.ccx();
-    let def = ccx.tcx.def_map.borrow().get_copy(&pat_id);
-    match def {
-        def::DefVariant(enum_id, var_id, _) => {
-            let variant = ty::enum_variant_with_id(ccx.tcx(), enum_id, var_id);
-            var(variant.disr_val, adt::represent_node(bcx, pat_id), var_id)
-        }
-        _ => {
-            ccx.sess().bug("non-variant or struct in variant_opt()");
-        }
-    }
-}
-
 #[deriving(Clone)]
 pub enum TransBindingMode {
     TrByCopy(/* llbinding */ ValueRef),
@@ -630,26 +614,15 @@ fn add_veclen_to_set(set: &mut Vec<Opt> , i: uint,
             ast::PatLit(l) => {
                 add_to_set(ccx.tcx(), &mut found, lit(l));
             }
-            ast::PatIdent(..) => {
+            ast::PatIdent(..) | ast::PatEnum(..) | ast::PatStruct(..) => {
                 // This is either an enum variant or a variable binding.
                 let opt_def = ccx.tcx.def_map.borrow().find_copy(&cur.id);
                 match opt_def {
-                    Some(def::DefVariant(..)) => {
-                        add_to_set(ccx.tcx(), &mut found,
-                                   variant_opt(bcx, cur.id));
-                    }
-                    _ => {}
-                }
-            }
-            ast::PatEnum(..) | ast::PatStruct(..) => {
-                // This could be one of: a tuple-like enum variant, a
-                // struct-like enum variant, or a struct.
-                let opt_def = ccx.tcx.def_map.borrow().find_copy(&cur.id);
-                match opt_def {
-                    Some(def::DefFn(..)) |
-                    Some(def::DefVariant(..)) => {
+                    Some(def::DefVariant(enum_id, var_id, _)) => {
+                        let variant = ty::enum_variant_with_id(ccx.tcx(), enum_id, var_id);
                         add_to_set(ccx.tcx(), &mut found,
-                                   variant_opt(bcx, cur.id));
+                                   var(variant.disr_val,
+                                       adt::represent_node(bcx, cur.id), var_id));
                     }
                     _ => {}
                 }
@@ -795,40 +768,18 @@ fn any_irrefutable_adt_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
     })
 }
 
-struct DynamicFailureHandler<'a> {
-    bcx: &'a Block<'a>,
-    sp: Span,
-    msg: InternedString,
-    finished: Cell<Option<BasicBlockRef>>,
-}
-
-impl<'a> DynamicFailureHandler<'a> {
-    fn handle_fail(&self) -> BasicBlockRef {
-        match self.finished.get() {
-            Some(bb) => return bb,
-            _ => (),
-        }
-
-        let fcx = self.bcx.fcx;
-        let fail_cx = fcx.new_block(false, "case_fallthrough", None);
-        controlflow::trans_fail(fail_cx, self.sp, self.msg.clone());
-        self.finished.set(Some(fail_cx.llbb));
-        fail_cx.llbb
-    }
-}
-
 /// What to do when the pattern match fails.
 enum FailureHandler<'a> {
     Infallible,
     JumpToBasicBlock(BasicBlockRef),
-    DynamicFailureHandlerClass(Box<DynamicFailureHandler<'a>>),
+    Unreachable
 }
 
 impl<'a> FailureHandler<'a> {
     fn is_infallible(&self) -> bool {
         match *self {
             Infallible => true,
-            _ => false,
+            _ => false
         }
     }
 
@@ -836,15 +787,14 @@ fn is_fallible(&self) -> bool {
         !self.is_infallible()
     }
 
-    fn handle_fail(&self) -> BasicBlockRef {
+    fn handle_fail(&self, bcx: &Block) {
         match *self {
-            Infallible => {
-                fail!("attempted to fail in infallible failure handler!")
-            }
-            JumpToBasicBlock(basic_block) => basic_block,
-            DynamicFailureHandlerClass(ref dynamic_failure_handler) => {
-                dynamic_failure_handler.handle_fail()
-            }
+            Infallible =>
+                fail!("attempted to fail in infallible failure handler!"),
+            JumpToBasicBlock(basic_block) =>
+                Br(bcx, basic_block),
+            Unreachable =>
+                build::Unreachable(bcx)
         }
     }
 }
@@ -1005,7 +955,7 @@ fn compile_guard<'a, 'b>(
             // condition explicitly rather than (possibly) falling back to
             // the default arm.
             &JumpToBasicBlock(_) if m.len() == 1 && has_genuine_default => {
-                Br(bcx, chk.handle_fail());
+                chk.handle_fail(bcx);
             }
             _ => {
                 compile_submatch(bcx, m, vals, chk, has_genuine_default);
@@ -1030,7 +980,7 @@ fn compile_submatch<'a, 'b>(
     let mut bcx = bcx;
     if m.len() == 0u {
         if chk.is_fallible() {
-            Br(bcx, chk.handle_fail());
+            chk.handle_fail(bcx);
         }
         return;
     }
@@ -1301,7 +1251,7 @@ fn compile_submatch_continue<'a, 'b>(
             // condition explicitly rather than (eventually) falling back to
             // the last default arm.
             &JumpToBasicBlock(_) if defaults.len() == 1 && has_genuine_default => {
-                Br(else_cx, chk.handle_fail());
+                chk.handle_fail(else_cx);
             }
             _ => {
                 compile_submatch(else_cx,
@@ -1395,21 +1345,10 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
     }
 
     let t = node_id_type(bcx, discr_expr.id);
-    let chk = {
-        if ty::type_is_empty(tcx, t) {
-            // Special case for empty types
-            let fail_cx = Cell::new(None);
-            let fail_handler = box DynamicFailureHandler {
-                bcx: scope_cx,
-                sp: discr_expr.span,
-                msg: InternedString::new("scrutinizing value that can't \
-                                          exist"),
-                finished: fail_cx,
-            };
-            DynamicFailureHandlerClass(fail_handler)
-        } else {
-            Infallible
-        }
+    let chk = if ty::type_is_empty(tcx, t) {
+        Unreachable
+    } else {
+        Infallible
     };
 
     let arm_datas: Vec<ArmData> = arms.iter().map(|arm| ArmData {
index c8f6836b20596cd9e98b0e6c10267a745dcc17d6..637af96b6321ab23cb2e0521922e89a8e345ff5d 100644 (file)
@@ -117,7 +117,7 @@ fn test_env(_test_name: &str,
     let input = driver::StrInput(source_string.to_string());
     let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
     let (krate, ast_map) =
-        driver::phase_2_configure_and_expand(&sess, krate, "test")
+        driver::phase_2_configure_and_expand(&sess, krate, "test", None)
             .expect("phase 2 aborted");
 
     // run just enough stuff to build a tcx:
index 499cffa42aac9f124913adb549a0c81175765ffc..4f38c74893e46630c08420440a49160938272d37 100644 (file)
@@ -66,10 +66,24 @@ fn new(sess: &'a Session) -> PluginLoader<'a> {
 }
 
 /// Read plugin metadata and dynamically load registrar functions.
-pub fn load_plugins(sess: &Session, krate: &ast::Crate) -> Plugins {
+pub fn load_plugins(sess: &Session, krate: &ast::Crate,
+                    addl_plugins: Option<Plugins>) -> Plugins {
     let mut loader = PluginLoader::new(sess);
     visit::walk_crate(&mut loader, krate, ());
-    loader.plugins
+
+    let mut plugins = loader.plugins;
+
+    match addl_plugins {
+        Some(addl_plugins) => {
+            // Add in the additional plugins requested by the frontend
+            let Plugins { macros: addl_macros, registrars: addl_registrars } = addl_plugins;
+            plugins.macros.push_all_move(addl_macros);
+            plugins.registrars.push_all_move(addl_registrars);
+        }
+        None => ()
+    }
+
+    return plugins;
 }
 
 // note that macros aren't expanded yet, and therefore macros can't add plugins.
index e62c8b63a294070b0c873f5cccecc9775b22a24f..7f021510f4a0ed85838d81f036856df189155a29 100644 (file)
@@ -77,8 +77,10 @@ pub struct CrateAnalysis {
     pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
 }
 
+pub type Externs = HashMap<String, Vec<String>>;
+
 /// Parses, resolves, and typechecks the given crate
-fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
+fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>, externs: Externs)
                        -> (DocContext, CrateAnalysis) {
     use syntax::codemap::dummy_spanned;
     use rustc::driver::driver::{FileInput,
@@ -96,6 +98,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
         addl_lib_search_paths: RefCell::new(libs),
         crate_types: vec!(driver::config::CrateTypeRlib),
         lint_opts: vec!((warning_lint, lint::Allow)),
+        externs: externs,
         ..rustc::driver::config::basic_options().clone()
     };
 
@@ -121,7 +124,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
                                      &input);
 
     let (krate, ast_map)
-        = phase_2_configure_and_expand(&sess, krate, name.as_slice())
+        = phase_2_configure_and_expand(&sess, krate, name.as_slice(), None)
             .expect("phase_2_configure_and_expand aborted in rustdoc!");
 
     let driver::driver::CrateAnalysis {
@@ -148,9 +151,9 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
     })
 }
 
-pub fn run_core(libs: HashSet<Path>, cfgs: Vec<String>, path: &Path)
+pub fn run_core(libs: HashSet<Path>, cfgs: Vec<String>, externs: Externs, path: &Path)
                 -> (clean::Crate, CrateAnalysis) {
-    let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs);
+    let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs, externs);
     let ctxt = box(GC) ctxt;
     super::ctxtkey.replace(Some(ctxt));
 
index 245dc9a0a34e5cbef07bb60834c86814109357f0..a7c9ac10118296b3830270a6af0b918aa14d18d3 100644 (file)
@@ -30,6 +30,7 @@
 use std::io;
 use std::io::{File, MemWriter};
 use std::gc::Gc;
+use std::collections::HashMap;
 use serialize::{json, Decodable, Encodable};
 use externalfiles::ExternalHtml;
 
@@ -104,6 +105,7 @@ pub fn opts() -> Vec<getopts::OptGroup> {
         optmulti("L", "library-path", "directory to add to crate search path",
                  "DIR"),
         optmulti("", "cfg", "pass a --cfg to rustc", ""),
+        optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH"),
         optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
         optmulti("", "passes", "space separated list of passes to also run, a \
                                 value of `list` will print available passes",
@@ -170,6 +172,13 @@ pub fn main_args(args: &[String]) -> int {
     let input = matches.free[0].as_slice();
 
     let libs = matches.opt_strs("L").iter().map(|s| Path::new(s.as_slice())).collect();
+    let externs = match parse_externs(&matches) {
+        Ok(ex) => ex,
+        Err(err) => {
+            println!("{}", err);
+            return 1;
+        }
+    };
 
     let test_args = matches.opt_strs("test-args");
     let test_args: Vec<String> = test_args.iter()
@@ -193,10 +202,10 @@ pub fn main_args(args: &[String]) -> int {
 
     match (should_test, markdown_input) {
         (true, true) => {
-            return markdown::test(input, libs, test_args)
+            return markdown::test(input, libs, externs, test_args)
         }
         (true, false) => {
-            return test::run(input, cfgs, libs, test_args)
+            return test::run(input, cfgs, libs, externs, test_args)
         }
         (false, true) => return markdown::render(input, output.unwrap_or(Path::new("doc")),
                                                  &matches, &external_html),
@@ -215,7 +224,7 @@ pub fn main_args(args: &[String]) -> int {
         return 0;
     }
 
-    let (krate, res) = match acquire_input(input, &matches) {
+    let (krate, res) = match acquire_input(input, externs, &matches) {
         Ok(pair) => pair,
         Err(s) => {
             println!("input error: {}", s);
@@ -252,27 +261,53 @@ pub fn main_args(args: &[String]) -> int {
 /// Looks inside the command line arguments to extract the relevant input format
 /// and files and then generates the necessary rustdoc output for formatting.
 fn acquire_input(input: &str,
+                 externs: core::Externs,
                  matches: &getopts::Matches) -> Result<Output, String> {
     match matches.opt_str("r").as_ref().map(|s| s.as_slice()) {
-        Some("rust") => Ok(rust_input(input, matches)),
+        Some("rust") => Ok(rust_input(input, externs, matches)),
         Some("json") => json_input(input),
         Some(s) => Err(format!("unknown input format: {}", s)),
         None => {
             if input.ends_with(".json") {
                 json_input(input)
             } else {
-                Ok(rust_input(input, matches))
+                Ok(rust_input(input, externs, matches))
             }
         }
     }
 }
 
+/// Extracts `--extern CRATE=PATH` arguments from `matches` and
+/// returns a `HashMap` mapping crate names to their paths or else an
+/// error message.
+fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> {
+    let mut externs = HashMap::new();
+    for arg in matches.opt_strs("extern").iter() {
+        let mut parts = arg.as_slice().splitn('=', 1);
+        let name = match parts.next() {
+            Some(s) => s,
+            None => {
+                return Err("--extern value must not be empty".to_string());
+            }
+        };
+        let location = match parts.next() {
+            Some(s) => s,
+            None => {
+                return Err("--extern value must be of the format `foo=bar`".to_string());
+            }
+        };
+        let locs = externs.find_or_insert(name.to_string(), Vec::new());
+        locs.push(location.to_string());
+    }
+    Ok(externs)
+}
+
 /// Interprets the input file as a rust source file, passing it through the
 /// compiler all the way through the analysis passes. The rustdoc output is then
 /// generated from the cleaned AST of the crate.
 ///
 /// This form of input will run all of the plug/cleaning passes
-fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
+fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matches) -> Output {
     let mut default_passes = !matches.opt_present("no-defaults");
     let mut passes = matches.opt_strs("passes");
     let mut plugins = matches.opt_strs("plugins");
@@ -283,12 +318,14 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
                                  .map(|s| Path::new(s.as_slice()))
                                  .collect();
     let cfgs = matches.opt_strs("cfg");
+
     let cr = Path::new(cratefile);
     info!("starting to run rustc");
     let (krate, analysis) = std::task::try(proc() {
         let cr = cr;
-        core::run_core(libs.move_iter().map(|x| x.clone()).collect(),
+        core::run_core(libs.move_iter().collect(),
                        cfgs,
+                       externs,
                        &cr)
     }).map_err(|boxed_any|format!("{:?}", boxed_any)).unwrap();
     info!("finished with rustc");
index f9bc59888ae3b9704f09668929799afc3b24403c..47009c1f2cc15ef8cc447fdadc002fc2e4e248ea 100644 (file)
@@ -12,6 +12,7 @@
 use std::io;
 use std::string::String;
 
+use core;
 use getopts;
 use testing;
 
@@ -129,10 +130,11 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches,
 }
 
 /// Run any tests/code examples in the markdown file `input`.
-pub fn test(input: &str, libs: HashSet<Path>, mut test_args: Vec<String>) -> int {
+pub fn test(input: &str, libs: HashSet<Path>, externs: core::Externs,
+            mut test_args: Vec<String>) -> int {
     let input_str = load_or_return!(input, 1, 2);
 
-    let mut collector = Collector::new(input.to_string(), libs, true);
+    let mut collector = Collector::new(input.to_string(), libs, externs, true);
     find_testable_code(input_str.as_slice(), &mut collector);
     test_args.unshift("rustdoctest".to_string());
     testing::test_main(test_args.as_slice(), collector.tests);
index 055019aa481ffebaf06edc9aab9f3a467be8efd8..2ed35469dfa8d127db57e0bc66819d339a9206b9 100644 (file)
@@ -40,6 +40,7 @@
 pub fn run(input: &str,
            cfgs: Vec<String>,
            libs: HashSet<Path>,
+           externs: core::Externs,
            mut test_args: Vec<String>)
            -> int {
     let input_path = Path::new(input);
@@ -49,10 +50,10 @@ pub fn run(input: &str,
         maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
         addl_lib_search_paths: RefCell::new(libs.clone()),
         crate_types: vec!(config::CrateTypeDylib),
+        externs: externs.clone(),
         ..config::basic_options().clone()
     };
 
-
     let codemap = CodeMap::new();
     let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
     let span_diagnostic_handler =
@@ -69,7 +70,7 @@ pub fn run(input: &str,
     }));
     let krate = driver::phase_1_parse_input(&sess, cfg, &input);
     let (krate, _) = driver::phase_2_configure_and_expand(&sess, krate,
-                                                          "rustdoc-test")
+                                                          "rustdoc-test", None)
         .expect("phase_2_configure_and_expand aborted in rustdoc!");
 
     let ctx = box(GC) core::DocContext {
@@ -92,6 +93,7 @@ pub fn run(input: &str,
 
     let mut collector = Collector::new(krate.name.to_string(),
                                        libs,
+                                       externs,
                                        false);
     collector.fold_crate(krate);
 
@@ -102,8 +104,8 @@ pub fn run(input: &str,
     0
 }
 
-fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
-           no_run: bool, as_test_harness: bool) {
+fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, externs: core::Externs,
+           should_fail: bool, no_run: bool, as_test_harness: bool) {
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
     let test = maketest(test, Some(cratename), true, as_test_harness);
@@ -115,6 +117,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
         crate_types: vec!(config::CrateTypeExecutable),
         output_types: vec!(link::OutputTypeExe),
         no_trans: no_run,
+        externs: externs,
         cg: config::CodegenOptions {
             prefer_dynamic: true,
             .. config::basic_codegen_options()
@@ -166,7 +169,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
     let out = Some(outdir.path().clone());
     let cfg = config::build_configuration(&sess);
     let libdir = sess.target_filesearch().get_lib_path();
-    driver::compile_input(sess, cfg, &input, &out, &None);
+    driver::compile_input(sess, cfg, &input, &out, &None, None);
 
     if no_run { return }
 
@@ -237,6 +240,7 @@ pub struct Collector {
     pub tests: Vec<testing::TestDescAndFn>,
     names: Vec<String>,
     libs: HashSet<Path>,
+    externs: core::Externs,
     cnt: uint,
     use_headers: bool,
     current_header: Option<String>,
@@ -244,12 +248,13 @@ pub struct Collector {
 }
 
 impl Collector {
-    pub fn new(cratename: String, libs: HashSet<Path>,
+    pub fn new(cratename: String, libs: HashSet<Path>, externs: core::Externs,
                use_headers: bool) -> Collector {
         Collector {
             tests: Vec::new(),
             names: Vec::new(),
             libs: libs,
+            externs: externs,
             cnt: 0,
             use_headers: use_headers,
             current_header: None,
@@ -267,6 +272,7 @@ pub fn add_test(&mut self, test: String,
         };
         self.cnt += 1;
         let libs = self.libs.clone();
+        let externs = self.externs.clone();
         let cratename = self.cratename.to_string();
         debug!("Creating test {}: {}", name, test);
         self.tests.push(testing::TestDescAndFn {
@@ -279,6 +285,7 @@ pub fn add_test(&mut self, test: String,
                 runtest(test.as_slice(),
                         cratename.as_slice(),
                         libs,
+                        externs,
                         should_fail,
                         no_run,
                         as_test_harness);
index c8f9ed64a77f8f7bed411a1dba8d5ae7bcf49a06..594a235339669694357c7693e11a061dfa1cf6c7 100644 (file)
 use core;
 use doctree::*;
 
+// looks to me like the first two of these are actually
+// output parameters, maybe only mutated once; perhaps
+// better simply to have the visit method return a tuple
+// containing them?
+
+// also, is there some reason that this doesn't use the 'visit'
+// framework from syntax?
+
 pub struct RustdocVisitor<'a> {
     pub module: Module,
     pub attrs: Vec<ast::Attribute>,
@@ -64,6 +72,9 @@ pub fn visit(&mut self, krate: &ast::Crate) {
                                               ast::CRATE_NODE_ID,
                                               &krate.module,
                                               None);
+        // attach the crate's exported macros to the top-level module:
+        self.module.macros = krate.exported_macros.iter()
+            .map(|it| self.visit_macro(&**it)).collect();
         self.module.is_crate = true;
     }
 
@@ -323,15 +334,20 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
             ast::ItemForeignMod(ref fm) => {
                 om.foreigns.push(fm.clone());
             }
-            ast::ItemMac(ref _m) => {
-                om.macros.push(Macro {
-                    id: item.id,
-                    attrs: item.attrs.iter().map(|x| *x).collect(),
-                    name: item.ident,
-                    where: item.span,
-                    stab: self.stability(item.id),
-                })
+            ast::ItemMac(_) => {
+                fail!("rustdoc: macros should be gone, after expansion");
             }
         }
     }
+
+    // convert each exported_macro into a doc item
+    fn visit_macro(&self, item: &ast::Item) -> Macro {
+        Macro {
+            id: item.id,
+            attrs: item.attrs.iter().map(|x| *x).collect(),
+            name: item.ident,
+            where: item.span,
+            stab: self.stability(item.id),
+        }
+    }
 }
index 40c3e19576e4fa304467661d73aa8028da28325e..1334000ed1f5c7ffb59bc619dc2a8a31557b00c9 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15677
 
 use core::prelude::*;
 
index 79c1d6554113f1b665e6c7e381c582f4aaf30d7d..5e8648d355ebfd025fcd35a69d0492a009c2a167 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! Base64 binary-to-text encoding
 use std::str;
index 3083c06c8773f5d1bd9a075eb51325bee168a490..d6a029c583cd25e896554f9d1fd9f9c75dc39bcd 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! Hex binary-to-text encoding
 use std::str;
index b9c86e2b23586b49b22ad845e677b90ba79002ea..02cb5dd245b7cbdf3b852f43e9d0be60523899ed 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! Operations on ASCII strings and characters
 
@@ -20,7 +22,7 @@
 use slice::{ImmutableVector, MutableVector, Vector};
 use str::{OwnedStr, Str, StrAllocating, StrSlice};
 use string::String;
-use to_str::{IntoStr};
+use to_string::IntoStr;
 use vec::Vec;
 
 /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
index 14027bc1f544fd868dbd0fd3df90742d36dae616..a05fad3705dd54ce28b367d1325b9bca36492679 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 //! Unordered containers, implemented as hash-tables (`HashSet` and `HashMap` types)
 
index b9c6220c0e2de8751a63880c332264a4e3a75981..2182c43d4a0c2b9209479663950d804bba0aea96 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 /*!
 
index 4f355502eb88d3a9d5b742f2e91942722bbc5cdc..e25006a7b39521889e320ef5f99723b520beee47 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 //! Buffering wrappers for I/O traits
 
index d49c56b4704402dfa77ea958a77a3e6aabe993ed..afd88ee0ed91b05d93369480c508eb5e1ae7a08d 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 /*! Synchronous File I/O
 
index 1c0251c8369dedc4a8709d8f1cc74ae60c7edcc4..b93b84b7d63f3a6dc5eedb524f8bf6f5629e88ac 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! Readers and Writers for in-memory buffers
 
index c0fddcb2ae5b5adf29890468dced1af972edd154..4277b509962cca1bdd14df052d03c2c0ab71cc4f 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 // FIXME: cover these topics:
 //        path, reader, writer, stream, raii (close not needed),
index ad6942712ac9af3f484a3619a6e5d2d88cfcb937..e14092bc8dc1604e04b29883d24396bf480b95fa 100644 (file)
@@ -239,7 +239,7 @@ fn start(argc: int, argv: *const *const u8) -> int {
 
 pub mod from_str;
 pub mod num;
-pub mod to_str;
+pub mod to_string;
 
 /* Common data structures */
 
index 88fc6e1ffd85f743be2e01d6365887f3643ecbf7..cc30acf064b8257fac2db9f8b0907684d0c5a6f0 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 #![allow(missing_doc)]
 
index 02d9dc4448984252ab36b372b8eff54dc609f758..4a6ed5612334c5bf9c4ebd87d928bf79fdf28410 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 //! Windows file path handling
 
index eee494c7bc0a1e218808812459dedfe88569a81c..0fa223305a669d36fb929c9896d864e85768e9bd 100644 (file)
@@ -78,7 +78,7 @@
 #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek};
 #[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr};
 #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrSlice};
-#[doc(no_inline)] pub use to_str::{ToString, IntoStr};
+#[doc(no_inline)] pub use to_string::{ToString, IntoStr};
 #[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
 #[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
 #[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
index 4b8c15a0152a39f2316070c172c82a578267131e..19ad81a04834d606ebaa613928f281f6bf8a220f 100644 (file)
 use str::{Str, SendStr, IntoMaybeOwned};
 use string::String;
 use sync::Future;
-use to_str::ToString;
+use to_string::ToString;
 
 /// A means of spawning a task
 pub trait Spawner {
diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs
deleted file mode 100644 (file)
index c19fd81..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-The `ToString` trait for converting to strings
-
-*/
-
-#![experimental]
-
-use fmt;
-use string::String;
-
-/// A generic trait for converting a value to a string
-pub trait ToString {
-    /// Converts the value of `self` to an owned string
-    fn to_string(&self) -> String;
-}
-
-/// Trait for converting a type to a string, consuming it in the process.
-pub trait IntoStr {
-    /// Consume and convert to a string.
-    fn into_string(self) -> String;
-}
-
-impl<T: fmt::Show> ToString for T {
-    fn to_string(&self) -> String {
-        format!("{}", *self)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use prelude::*;
-    use super::*;
-
-    #[test]
-    fn test_simple_types() {
-        assert_eq!(1i.to_string(), "1".to_string());
-        assert_eq!((-1i).to_string(), "-1".to_string());
-        assert_eq!(200u.to_string(), "200".to_string());
-        assert_eq!(2u8.to_string(), "2".to_string());
-        assert_eq!(true.to_string(), "true".to_string());
-        assert_eq!(false.to_string(), "false".to_string());
-        assert_eq!(().to_string(), "()".to_string());
-        assert_eq!(("hi".to_string()).to_string(), "hi".to_string());
-    }
-
-    #[test]
-    fn test_vectors() {
-        let x: Vec<int> = vec![];
-        assert_eq!(x.to_string(), "[]".to_string());
-        assert_eq!((vec![1i]).to_string(), "[1]".to_string());
-        assert_eq!((vec![1i, 2, 3]).to_string(), "[1, 2, 3]".to_string());
-        assert!((vec![vec![], vec![1i], vec![1i, 1]]).to_string() ==
-               "[[], [1], [1, 1]]".to_string());
-    }
-}
diff --git a/src/libstd/to_string.rs b/src/libstd/to_string.rs
new file mode 100644 (file)
index 0000000..c19fd81
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+
+The `ToString` trait for converting to strings
+
+*/
+
+#![experimental]
+
+use fmt;
+use string::String;
+
+/// A generic trait for converting a value to a string
+pub trait ToString {
+    /// Converts the value of `self` to an owned string
+    fn to_string(&self) -> String;
+}
+
+/// Trait for converting a type to a string, consuming it in the process.
+pub trait IntoStr {
+    /// Consume and convert to a string.
+    fn into_string(self) -> String;
+}
+
+impl<T: fmt::Show> ToString for T {
+    fn to_string(&self) -> String {
+        format!("{}", *self)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::*;
+
+    #[test]
+    fn test_simple_types() {
+        assert_eq!(1i.to_string(), "1".to_string());
+        assert_eq!((-1i).to_string(), "-1".to_string());
+        assert_eq!(200u.to_string(), "200".to_string());
+        assert_eq!(2u8.to_string(), "2".to_string());
+        assert_eq!(true.to_string(), "true".to_string());
+        assert_eq!(false.to_string(), "false".to_string());
+        assert_eq!(().to_string(), "()".to_string());
+        assert_eq!(("hi".to_string()).to_string(), "hi".to_string());
+    }
+
+    #[test]
+    fn test_vectors() {
+        let x: Vec<int> = vec![];
+        assert_eq!(x.to_string(), "[]".to_string());
+        assert_eq!((vec![1i]).to_string(), "[1]".to_string());
+        assert_eq!((vec![1i, 2, 3]).to_string(), "[1, 2, 3]".to_string());
+        assert!((vec![vec![], vec![1i], vec![1i, 1]]).to_string() ==
+               "[[], [1], [1, 1]]".to_string());
+    }
+}
index 7ad9a18a15e1b3b27b62a68458138e922ad5f708..614bbd1c3ed00f4e5592891798e2ee22aca65d68 100644 (file)
@@ -256,7 +256,7 @@ pub struct Crate {
     pub attrs: Vec<Attribute>,
     pub config: CrateConfig,
     pub span: Span,
-    pub exported_macros: Vec<Span>
+    pub exported_macros: Vec<Gc<Item>>
 }
 
 pub type MetaItem = Spanned<MetaItem_>;
index ef4024a8f83fe0cabb79fda2d0250998c747db17..2f30108c27bd118bc9f955760443665aebeff0c0 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 /*!
 
index 49bd3697884c72750ff2455ca8cffbc91ea1a4ed..a66d6839ab0743d5d5884c8507b1515a4784b07d 100644 (file)
 use parse::token::{InternedString, intern, str_to_ident};
 use util::small_vector::SmallVector;
 use ext::mtwt;
+use fold::Folder;
 
 use std::collections::HashMap;
 use std::gc::{Gc, GC};
+use std::rc::Rc;
 
 // new-style macro! tt code:
 //
@@ -314,7 +316,7 @@ pub fn new() -> BlockInfo {
 
 /// The base map of methods for expanding syntax extension
 /// AST nodes into full ASTs
-pub fn syntax_expander_table() -> SyntaxEnv {
+fn initial_syntax_expander_table() -> SyntaxEnv {
     // utility function to simplify creating NormalTT syntax extensions
     fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
         NormalTT(box BasicMacroExpander {
@@ -431,7 +433,9 @@ pub struct ExtCtxt<'a> {
 
     pub mod_path: Vec<ast::Ident> ,
     pub trace_mac: bool,
-    pub exported_macros: Vec<codemap::Span>
+    pub exported_macros: Vec<Gc<ast::Item>>,
+
+    pub syntax_env: SyntaxEnv,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -445,22 +449,18 @@ pub fn new<'a>(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
             ecfg: ecfg,
             trace_mac: false,
             exported_macros: Vec::new(),
+            syntax_env: initial_syntax_expander_table(),
         }
     }
 
-    pub fn expand_expr(&mut self, mut e: Gc<ast::Expr>) -> Gc<ast::Expr> {
-        loop {
-            match e.node {
-                ast::ExprMac(..) => {
-                    let mut expander = expand::MacroExpander {
-                        extsbox: syntax_expander_table(),
-                        cx: self,
-                    };
-                    e = expand::expand_expr(e, &mut expander);
-                }
-                _ => return e
-            }
-        }
+    #[deprecated = "Replaced with `expander().fold_expr()`"]
+    pub fn expand_expr(&mut self, e: Gc<ast::Expr>) -> Gc<ast::Expr> {
+        self.expander().fold_expr(e)
+    }
+
+    /// Returns a `Folder` for deeply expanding all macros in a AST node.
+    pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
+        expand::MacroExpander { cx: self }
     }
 
     pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
@@ -562,9 +562,6 @@ pub fn ident_of(&self, st: &str) -> ast::Ident {
     pub fn name_of(&self, st: &str) -> ast::Name {
         token::intern(st)
     }
-    pub fn push_exported_macro(&mut self, span: codemap::Span) {
-        self.exported_macros.push(span);
-    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
@@ -573,7 +570,7 @@ pub fn push_exported_macro(&mut self, span: codemap::Span) {
 pub fn expr_to_string(cx: &mut ExtCtxt, expr: Gc<ast::Expr>, err_msg: &str)
                    -> Option<(InternedString, ast::StrStyle)> {
     // we want to be able to handle e.g. concat("foo", "bar")
-    let expr = cx.expand_expr(expr);
+    let expr = cx.expander().fold_expr(expr);
     match expr.node {
         ast::ExprLit(l) => match l.node {
             ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
@@ -630,7 +627,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
     let mut p = cx.new_parser_from_tts(tts);
     let mut es = Vec::new();
     while p.token != token::EOF {
-        es.push(cx.expand_expr(p.parse_expr()));
+        es.push(cx.expander().fold_expr(p.parse_expr()));
         if p.eat(&token::COMMA) {
             continue;
         }
@@ -645,10 +642,13 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 /// In order to have some notion of scoping for macros,
 /// we want to implement the notion of a transformation
 /// environment.
-
+///
 /// This environment maps Names to SyntaxExtensions.
+pub struct SyntaxEnv {
+    chain: Vec<MapChainFrame> ,
+}
 
-//impl question: how to implement it? Initially, the
+// impl question: how to implement it? Initially, the
 // env will contain only macros, so it might be painful
 // to add an empty frame for every context. Let's just
 // get it working, first....
@@ -660,15 +660,11 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 
 struct MapChainFrame {
     info: BlockInfo,
-    map: HashMap<Name, SyntaxExtension>,
-}
-
-pub struct SyntaxEnv {
-    chain: Vec<MapChainFrame> ,
+    map: HashMap<Name, Rc<SyntaxExtension>>,
 }
 
 impl SyntaxEnv {
-    pub fn new() -> SyntaxEnv {
+    fn new() -> SyntaxEnv {
         let mut map = SyntaxEnv { chain: Vec::new() };
         map.push_frame();
         map
@@ -695,10 +691,10 @@ fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame {
         unreachable!()
     }
 
-    pub fn find<'a>(&'a self, k: &Name) -> Option<&'a SyntaxExtension> {
+    pub fn find(&self, k: &Name) -> Option<Rc<SyntaxExtension>> {
         for frame in self.chain.iter().rev() {
             match frame.map.find(k) {
-                Some(v) => return Some(v),
+                Some(v) => return Some(v.clone()),
                 None => {}
             }
         }
@@ -706,7 +702,7 @@ pub fn find<'a>(&'a self, k: &Name) -> Option<&'a SyntaxExtension> {
     }
 
     pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
-        self.find_escape_frame().map.insert(k, v);
+        self.find_escape_frame().map.insert(k, Rc::new(v));
     }
 
     pub fn info<'a>(&'a mut self) -> &'a mut BlockInfo {
index fdb698441fc0c0d48358a92837124755662725c0..123dcf366f440f57756decf58169029aeb4af22b 100644 (file)
@@ -32,7 +32,7 @@
 use std::gc::{Gc, GC};
 
 
-pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
+fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
     match e.node {
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
@@ -208,7 +208,7 @@ fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
             }
             let extname = pth.segments.get(0).identifier;
             let extnamestr = token::get_ident(extname);
-            match fld.extsbox.find(&extname.name) {
+            match fld.cx.syntax_env.find(&extname.name) {
                 None => {
                     fld.cx.span_err(
                         pth.span,
@@ -218,46 +218,48 @@ fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
                     // let compilation continue
                     None
                 }
-                Some(&NormalTT(ref expandfun, exp_span)) => {
-                    fld.cx.bt_push(ExpnInfo {
-                            call_site: *span,
-                            callee: NameAndSpan {
-                                name: extnamestr.get().to_string(),
-                                format: MacroBang,
-                                span: exp_span,
-                            },
-                        });
-                    let fm = fresh_mark();
-                    let marked_before = mark_tts(tts.as_slice(), fm);
-
-                    // The span that we pass to the expanders we want to
-                    // be the root of the call stack. That's the most
-                    // relevant span and it's the actual invocation of
-                    // the macro.
-                    let mac_span = original_span(fld.cx);
-
-                    let expanded = expandfun.expand(fld.cx,
-                                                    mac_span.call_site,
-                                                    marked_before.as_slice());
-                    let parsed = match parse_thunk(expanded) {
-                        Some(e) => e,
-                        None => {
-                            fld.cx.span_err(
-                                pth.span,
-                                format!("non-expression macro in expression position: {}",
-                                        extnamestr.get().as_slice()
-                                        ).as_slice());
-                            return None;
-                        }
-                    };
-                    Some(mark_thunk(parsed,fm))
-                }
-                _ => {
-                    fld.cx.span_err(
-                        pth.span,
-                        format!("'{}' is not a tt-style macro",
-                                extnamestr.get()).as_slice());
-                    None
+                Some(rc) => match *rc {
+                    NormalTT(ref expandfun, exp_span) => {
+                        fld.cx.bt_push(ExpnInfo {
+                                call_site: *span,
+                                callee: NameAndSpan {
+                                    name: extnamestr.get().to_string(),
+                                    format: MacroBang,
+                                    span: exp_span,
+                                },
+                            });
+                        let fm = fresh_mark();
+                        let marked_before = mark_tts(tts.as_slice(), fm);
+
+                        // The span that we pass to the expanders we want to
+                        // be the root of the call stack. That's the most
+                        // relevant span and it's the actual invocation of
+                        // the macro.
+                        let mac_span = original_span(fld.cx);
+
+                        let expanded = expandfun.expand(fld.cx,
+                                                        mac_span.call_site,
+                                                        marked_before.as_slice());
+                        let parsed = match parse_thunk(expanded) {
+                            Some(e) => e,
+                            None => {
+                                fld.cx.span_err(
+                                    pth.span,
+                                    format!("non-expression macro in expression position: {}",
+                                            extnamestr.get().as_slice()
+                                            ).as_slice());
+                                return None;
+                            }
+                        };
+                        Some(mark_thunk(parsed,fm))
+                    }
+                    _ => {
+                        fld.cx.span_err(
+                            pth.span,
+                            format!("'{}' is not a tt-style macro",
+                                    extnamestr.get()).as_slice());
+                        None
+                    }
                 }
             }
         }
@@ -288,10 +290,10 @@ fn expand_loop_block(loop_block: P<Block>,
             // The rename *must* be added to the enclosed syntax context for
             // `break` or `continue` to pick up because by definition they are
             // in a block enclosed by loop head.
-            fld.extsbox.push_frame();
-            fld.extsbox.info().pending_renames.push(rename);
+            fld.cx.syntax_env.push_frame();
+            fld.cx.syntax_env.info().pending_renames.push(rename);
             let expanded_block = expand_block_elts(&*loop_block, fld);
-            fld.extsbox.pop_frame();
+            fld.cx.syntax_env.pop_frame();
 
             (expanded_block, Some(renamed_ident))
         }
@@ -321,29 +323,32 @@ fn expand_item(it: Gc<ast::Item>, fld: &mut MacroExpander)
     for attr in it.attrs.iter() {
         let mname = attr.name();
 
-        match fld.extsbox.find(&intern(mname.get())) {
-            Some(&ItemDecorator(dec_fn)) => {
-                attr::mark_used(attr);
+        match fld.cx.syntax_env.find(&intern(mname.get())) {
+            Some(rc) => match *rc {
+                ItemDecorator(dec_fn) => {
+                    attr::mark_used(attr);
 
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: attr.span,
-                    callee: NameAndSpan {
-                        name: mname.get().to_string(),
-                        format: MacroAttribute,
-                        span: None
-                    }
-                });
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.get().to_string(),
+                            format: MacroAttribute,
+                            span: None
+                        }
+                    });
 
-                // we'd ideally decorator_items.push_all(expand_item(item, fld)),
-                // but that double-mut-borrows fld
-                let mut items: SmallVector<Gc<ast::Item>> = SmallVector::zero();
-                dec_fn(fld.cx, attr.span, attr.node.value, it,
-                       |item| items.push(item));
-                decorator_items.extend(items.move_iter()
-                    .flat_map(|item| expand_item(item, fld).move_iter()));
+                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
+                    // but that double-mut-borrows fld
+                    let mut items: SmallVector<Gc<ast::Item>> = SmallVector::zero();
+                    dec_fn(fld.cx, attr.span, attr.node.value, it,
+                        |item| items.push(item));
+                    decorator_items.extend(items.move_iter()
+                        .flat_map(|item| expand_item(item, fld).move_iter()));
 
-                fld.cx.bt_pop();
-            }
+                    fld.cx.bt_pop();
+                }
+                _ => new_attrs.push((*attr).clone()),
+            },
             _ => new_attrs.push((*attr).clone()),
         }
     }
@@ -353,7 +358,7 @@ fn expand_item(it: Gc<ast::Item>, fld: &mut MacroExpander)
         ast::ItemMod(_) | ast::ItemForeignMod(_) => {
             fld.cx.mod_push(it.ident);
             let macro_escape = contains_macro_escape(new_attrs.as_slice());
-            let result = with_exts_frame!(fld.extsbox,
+            let result = with_exts_frame!(fld.cx.syntax_env,
                                           macro_escape,
                                           noop_fold_item(&*it, fld));
             fld.cx.mod_pop();
@@ -377,8 +382,8 @@ fn expand_item_modifiers(mut it: Gc<ast::Item>, fld: &mut MacroExpander)
                          -> Gc<ast::Item> {
     // partition the attributes into ItemModifiers and others
     let (modifiers, other_attrs) = it.attrs.partitioned(|attr| {
-        match fld.extsbox.find(&intern(attr.name().get())) {
-            Some(&ItemModifier(_)) => true,
+        match fld.cx.syntax_env.find(&intern(attr.name().get())) {
+            Some(rc) => match *rc { ItemModifier(_) => true, _ => false },
             _ => false
         }
     });
@@ -395,20 +400,23 @@ fn expand_item_modifiers(mut it: Gc<ast::Item>, fld: &mut MacroExpander)
     for attr in modifiers.iter() {
         let mname = attr.name();
 
-        match fld.extsbox.find(&intern(mname.get())) {
-            Some(&ItemModifier(dec_fn)) => {
-                attr::mark_used(attr);
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: attr.span,
-                    callee: NameAndSpan {
-                        name: mname.get().to_string(),
-                        format: MacroAttribute,
-                        span: None,
-                    }
-                });
-                it = dec_fn(fld.cx, attr.span, attr.node.value, it);
-                fld.cx.bt_pop();
-            }
+        match fld.cx.syntax_env.find(&intern(mname.get())) {
+            Some(rc) => match *rc {
+                ItemModifier(dec_fn) => {
+                    attr::mark_used(attr);
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.get().to_string(),
+                            format: MacroAttribute,
+                            span: None,
+                        }
+                    });
+                    it = dec_fn(fld.cx, attr.span, attr.node.value, it);
+                    fld.cx.bt_pop();
+                }
+                _ => unreachable!()
+            },
             _ => unreachable!()
         }
     }
@@ -452,7 +460,7 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
     let extname = pth.segments.get(0).identifier;
     let extnamestr = token::get_ident(extname);
     let fm = fresh_mark();
-    let expanded = match fld.extsbox.find(&extname.name) {
+    let expanded = match fld.cx.syntax_env.find(&extname.name) {
         None => {
             fld.cx.span_err(pth.span,
                             format!("macro undefined: '{}!'",
@@ -461,70 +469,72 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
             return SmallVector::zero();
         }
 
-        Some(&NormalTT(ref expander, span)) => {
-            if it.ident.name != parse::token::special_idents::invalid.name {
-                fld.cx
-                   .span_err(pth.span,
-                             format!("macro {}! expects no ident argument, \
-                                      given '{}'",
-                                     extnamestr,
-                                     token::get_ident(it.ident)).as_slice());
-                return SmallVector::zero();
+        Some(rc) => match *rc {
+            NormalTT(ref expander, span) => {
+                if it.ident.name != parse::token::special_idents::invalid.name {
+                    fld.cx
+                    .span_err(pth.span,
+                                format!("macro {}! expects no ident argument, \
+                                        given '{}'",
+                                        extnamestr,
+                                        token::get_ident(it.ident)).as_slice());
+                    return SmallVector::zero();
+                }
+                fld.cx.bt_push(ExpnInfo {
+                    call_site: it.span,
+                    callee: NameAndSpan {
+                        name: extnamestr.get().to_string(),
+                        format: MacroBang,
+                        span: span
+                    }
+                });
+                // mark before expansion:
+                let marked_before = mark_tts(tts.as_slice(), fm);
+                expander.expand(fld.cx, it.span, marked_before.as_slice())
             }
-            fld.cx.bt_push(ExpnInfo {
-                call_site: it.span,
-                callee: NameAndSpan {
-                    name: extnamestr.get().to_string(),
-                    format: MacroBang,
-                    span: span
+            IdentTT(ref expander, span) => {
+                if it.ident.name == parse::token::special_idents::invalid.name {
+                    fld.cx.span_err(pth.span,
+                                    format!("macro {}! expects an ident argument",
+                                            extnamestr.get()).as_slice());
+                    return SmallVector::zero();
                 }
-            });
-            // mark before expansion:
-            let marked_before = mark_tts(tts.as_slice(), fm);
-            expander.expand(fld.cx, it.span, marked_before.as_slice())
-        }
-        Some(&IdentTT(ref expander, span)) => {
-            if it.ident.name == parse::token::special_idents::invalid.name {
-                fld.cx.span_err(pth.span,
-                                format!("macro {}! expects an ident argument",
-                                        extnamestr.get()).as_slice());
-                return SmallVector::zero();
+                fld.cx.bt_push(ExpnInfo {
+                    call_site: it.span,
+                    callee: NameAndSpan {
+                        name: extnamestr.get().to_string(),
+                        format: MacroBang,
+                        span: span
+                    }
+                });
+                // mark before expansion:
+                let marked_tts = mark_tts(tts.as_slice(), fm);
+                expander.expand(fld.cx, it.span, it.ident, marked_tts)
             }
-            fld.cx.bt_push(ExpnInfo {
-                call_site: it.span,
-                callee: NameAndSpan {
-                    name: extnamestr.get().to_string(),
-                    format: MacroBang,
-                    span: span
+            LetSyntaxTT(ref expander, span) => {
+                if it.ident.name == parse::token::special_idents::invalid.name {
+                    fld.cx.span_err(pth.span,
+                                    format!("macro {}! expects an ident argument",
+                                            extnamestr.get()).as_slice());
+                    return SmallVector::zero();
                 }
-            });
-            // mark before expansion:
-            let marked_tts = mark_tts(tts.as_slice(), fm);
-            expander.expand(fld.cx, it.span, it.ident, marked_tts)
-        }
-        Some(&LetSyntaxTT(ref expander, span)) => {
-            if it.ident.name == parse::token::special_idents::invalid.name {
-                fld.cx.span_err(pth.span,
-                                format!("macro {}! expects an ident argument",
+                fld.cx.bt_push(ExpnInfo {
+                    call_site: it.span,
+                    callee: NameAndSpan {
+                        name: extnamestr.get().to_string(),
+                        format: MacroBang,
+                        span: span
+                    }
+                });
+                // DON'T mark before expansion:
+                expander.expand(fld.cx, it.span, it.ident, tts)
+            }
+            _ => {
+                fld.cx.span_err(it.span,
+                                format!("{}! is not legal in item position",
                                         extnamestr.get()).as_slice());
                 return SmallVector::zero();
             }
-            fld.cx.bt_push(ExpnInfo {
-                call_site: it.span,
-                callee: NameAndSpan {
-                    name: extnamestr.get().to_string(),
-                    format: MacroBang,
-                    span: span
-                }
-            });
-            // DON'T mark before expansion:
-            expander.expand(fld.cx, it.span, it.ident, tts)
-        }
-        _ => {
-            fld.cx.span_err(it.span,
-                            format!("{}! is not legal in item position",
-                                    extnamestr.get()).as_slice());
-            return SmallVector::zero();
         }
     };
 
@@ -534,9 +544,9 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
             // result of expanding a LetSyntaxTT, and thus doesn't
             // need to be marked. Not that it could be marked anyway.
             // create issue to recommend refactoring here?
-            fld.extsbox.insert(intern(name.as_slice()), ext);
+            fld.cx.syntax_env.insert(intern(name.as_slice()), ext);
             if attr::contains_name(it.attrs.as_slice(), "macro_export") {
-                fld.cx.push_exported_macro(it.span);
+                fld.cx.exported_macros.push(it);
             }
             SmallVector::zero()
         }
@@ -641,7 +651,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
                         rename_fld.fold_pat(expanded_pat)
                     };
                     // add them to the existing pending renames:
-                    fld.extsbox.info().pending_renames.push_all_move(new_pending_renames);
+                    fld.cx.syntax_env.info().pending_renames.push_all_move(new_pending_renames);
                     // also, don't forget to expand the init:
                     let new_init_opt = init.map(|e| fld.fold_expr(e));
                     let rewritten_local =
@@ -742,7 +752,7 @@ fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec<ast::Ident> {
 // expand a block. pushes a new exts_frame, then calls expand_block_elts
 fn expand_block(blk: &Block, fld: &mut MacroExpander) -> P<Block> {
     // see note below about treatment of exts table
-    with_exts_frame!(fld.extsbox,false,
+    with_exts_frame!(fld.cx.syntax_env,false,
                      expand_block_elts(blk, fld))
 }
 
@@ -753,7 +763,7 @@ fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P<Block> {
         b.stmts.iter().flat_map(|x| {
             // perform all pending renames
             let renamed_stmt = {
-                let pending_renames = &mut fld.extsbox.info().pending_renames;
+                let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
                 let mut rename_fld = IdentRenamer{renames:pending_renames};
                 rename_fld.fold_stmt(&**x).expect_one("rename_fold didn't return one value")
             };
@@ -762,7 +772,7 @@ fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P<Block> {
         }).collect();
     let new_expr = b.expr.map(|x| {
         let expr = {
-            let pending_renames = &mut fld.extsbox.info().pending_renames;
+            let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
             let mut rename_fld = IdentRenamer{renames:pending_renames};
             rename_fld.fold_expr(x)
         };
@@ -795,7 +805,7 @@ fn expand_pat(p: Gc<ast::Pat>, fld: &mut MacroExpander) -> Gc<ast::Pat> {
     }
     let extname = pth.segments.get(0).identifier;
     let extnamestr = token::get_ident(extname);
-    let marked_after = match fld.extsbox.find(&extname.name) {
+    let marked_after = match fld.cx.syntax_env.find(&extname.name) {
         None => {
             fld.cx.span_err(pth.span,
                             format!("macro undefined: '{}!'",
@@ -804,43 +814,45 @@ fn expand_pat(p: Gc<ast::Pat>, fld: &mut MacroExpander) -> Gc<ast::Pat> {
             return DummyResult::raw_pat(p.span);
         }
 
-        Some(&NormalTT(ref expander, span)) => {
-            fld.cx.bt_push(ExpnInfo {
-                call_site: p.span,
-                callee: NameAndSpan {
-                    name: extnamestr.get().to_string(),
-                    format: MacroBang,
-                    span: span
-                }
-            });
-
-            let fm = fresh_mark();
-            let marked_before = mark_tts(tts.as_slice(), fm);
-            let mac_span = original_span(fld.cx);
-            let expanded = match expander.expand(fld.cx,
-                                   mac_span.call_site,
-                                   marked_before.as_slice()).make_pat() {
-                Some(e) => e,
-                None => {
-                    fld.cx.span_err(
-                        pth.span,
-                        format!(
-                            "non-pattern macro in pattern position: {}",
-                            extnamestr.get()
-                        ).as_slice()
-                    );
-                    return DummyResult::raw_pat(p.span);
-                }
-            };
+        Some(rc) => match *rc {
+            NormalTT(ref expander, span) => {
+                fld.cx.bt_push(ExpnInfo {
+                    call_site: p.span,
+                    callee: NameAndSpan {
+                        name: extnamestr.get().to_string(),
+                        format: MacroBang,
+                        span: span
+                    }
+                });
 
-            // mark after:
-            mark_pat(expanded,fm)
-        }
-        _ => {
-            fld.cx.span_err(p.span,
-                            format!("{}! is not legal in pattern position",
-                                    extnamestr.get()).as_slice());
-            return DummyResult::raw_pat(p.span);
+                let fm = fresh_mark();
+                let marked_before = mark_tts(tts.as_slice(), fm);
+                let mac_span = original_span(fld.cx);
+                let expanded = match expander.expand(fld.cx,
+                                    mac_span.call_site,
+                                    marked_before.as_slice()).make_pat() {
+                    Some(e) => e,
+                    None => {
+                        fld.cx.span_err(
+                            pth.span,
+                            format!(
+                                "non-pattern macro in pattern position: {}",
+                                extnamestr.get()
+                            ).as_slice()
+                        );
+                        return DummyResult::raw_pat(p.span);
+                    }
+                };
+
+                // mark after:
+                mark_pat(expanded,fm)
+            }
+            _ => {
+                fld.cx.span_err(p.span,
+                                format!("{}! is not legal in pattern position",
+                                        extnamestr.get()).as_slice());
+                return DummyResult::raw_pat(p.span);
+            }
         }
     };
 
@@ -975,7 +987,6 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: &ast::FnDecl, block: Gc<ast::Blo
 
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b> {
-    pub extsbox: SyntaxEnv,
     pub cx: &'a mut ExtCtxt<'b>,
 }
 
@@ -1039,16 +1050,15 @@ pub struct ExportedMacros {
 pub fn expand_crate(parse_sess: &parse::ParseSess,
                     cfg: ExpansionConfig,
                     // these are the macros being imported to this crate:
-                    macros: Vec<ExportedMacros>,
+                    imported_macros: Vec<ExportedMacros>,
                     user_exts: Vec<NamedSyntaxExtension>,
                     c: Crate) -> Crate {
     let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
     let mut expander = MacroExpander {
-        extsbox: syntax_expander_table(),
         cx: &mut cx,
     };
 
-    for ExportedMacros { crate_name, macros } in macros.move_iter() {
+    for ExportedMacros { crate_name, macros } in imported_macros.move_iter() {
         let name = format!("<{} macros>", token::get_ident(crate_name))
             .into_string();
 
@@ -1063,7 +1073,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
     }
 
     for (name, extension) in user_exts.move_iter() {
-        expander.extsbox.insert(name, extension);
+        expander.cx.syntax_env.insert(name, extension);
     }
 
     let mut ret = expander.fold_crate(c);
@@ -1337,16 +1347,6 @@ fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
         name_finder.ident_accumulator
     }
 
-    //fn expand_and_resolve(crate_str: @str) -> ast::crate {
-        //let expanded_ast = expand_crate_str(crate_str);
-        // println!("expanded: {:?}\n",expanded_ast);
-        //mtwt_resolve_crate(expanded_ast)
-    //}
-    //fn expand_and_resolve_and_pretty_print (crate_str: @str) -> String {
-        //let resolved_ast = expand_and_resolve(crate_str);
-        //pprust::to_string(&resolved_ast,fake_print_crate,get_ident_interner())
-    //}
-
     #[test] fn macro_tokens_should_match(){
         expand_crate_str(
             "macro_rules! m((a)=>(13)) fn main(){m!(a);}".to_string());
index 8fefd4656558983118deb5be0ebdcb3b58404784..b00924c15901612a509bf93d0f53e7e3d730f5da 100644 (file)
@@ -49,6 +49,9 @@ struct Context<'a, 'b> {
     name_types: HashMap<String, ArgumentType>,
     name_ordering: Vec<String>,
 
+    /// The latest consecutive literal strings
+    literal: Option<String>,
+
     /// Collection of the compiled `rt::Piece` structures
     pieces: Vec<Gc<ast::Expr>>,
     name_positions: HashMap<String, uint>,
@@ -367,17 +370,29 @@ fn trans_count(&self, c: parse::Count) -> Gc<ast::Expr> {
         }
     }
 
+    /// Translate the accumulated string literals to a static `rt::Piece`
+    fn trans_literal_string(&mut self) -> Option<Gc<ast::Expr>> {
+        let sp = self.fmtsp;
+        self.literal.take().map(|s| {
+            let s = token::intern_and_get_ident(s.as_slice());
+            self.ecx.expr_call_global(sp,
+                                      self.rtpath("String"),
+                                      vec!(
+                self.ecx.expr_str(sp, s)
+            ))
+        })
+    }
+
     /// Translate a `parse::Piece` to a static `rt::Piece`
-    fn trans_piece(&mut self, piece: &parse::Piece) -> Gc<ast::Expr> {
+    fn trans_piece(&mut self, piece: &parse::Piece) -> Option<Gc<ast::Expr>> {
         let sp = self.fmtsp;
         match *piece {
             parse::String(s) => {
-                let s = token::intern_and_get_ident(s);
-                self.ecx.expr_call_global(sp,
-                                          self.rtpath("String"),
-                                          vec!(
-                    self.ecx.expr_str(sp, s)
-                ))
+                match self.literal {
+                    Some(ref mut sb) => sb.push_str(s),
+                    ref mut empty => *empty = Some(String::from_str(s)),
+                }
+                None
             }
             parse::Argument(ref arg) => {
                 // Translate the position
@@ -435,7 +450,7 @@ fn trans_piece(&mut self, piece: &parse::Piece) -> Gc<ast::Expr> {
                 let s = self.ecx.expr_struct(sp, path, vec!(
                     self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
                     self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt)));
-                self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s))
+                Some(self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s)))
             }
         }
     }
@@ -699,6 +714,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         name_ordering: name_ordering,
         nest_level: 0,
         next_arg: 0,
+        literal: None,
         pieces: Vec::new(),
         method_statics: Vec::new(),
         fmtsp: sp,
@@ -717,8 +733,14 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
             Some(piece) => {
                 if parser.errors.len() > 0 { break }
                 cx.verify_piece(&piece);
-                let piece = cx.trans_piece(&piece);
-                cx.pieces.push(piece);
+                match cx.trans_piece(&piece) {
+                    Some(piece) => {
+                        cx.trans_literal_string().map(|piece|
+                                                      cx.pieces.push(piece));
+                        cx.pieces.push(piece);
+                    }
+                    None => {}
+                }
             }
             None => break
         }
@@ -732,6 +754,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         }
         None => {}
     }
+    cx.trans_literal_string().map(|piece| cx.pieces.push(piece));
 
     // Make sure that all arguments were used and all arguments have types.
     for (i, ty) in cx.arg_types.iter().enumerate() {
index bdf1f6eb6007e3bc2454069b26b905ad2a11b846..509d5bd442182e78b1c1cc3b1c7032ffe57bea54 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 //! This is an Earley-like parser, without support for in-grammar nonterminals,
 //! only by calling out to the main rust parser for named nonterminals (which it
index e31ec0486538444a9fbb02b4503f0a49fedaa69d..271eee7d08a039db2a196b26630cef891698bb28 100644 (file)
@@ -752,7 +752,7 @@ pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
         attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
         config: c.config.iter().map(|x| fold_meta_item_(*x, folder)).collect(),
         span: folder.new_span(c.span),
-        exported_macros: c.exported_macros.iter().map(|sp| folder.new_span(*sp)).collect(),
+        exported_macros: c.exported_macros
     }
 }
 
index 15c5fa6b75a5ab6492b6f36681e2d25eb32feab9..46e2ca03ef6ed5b6f71a7ab05153a608f8574411 100644 (file)
@@ -842,7 +842,6 @@ fn len_if_padded(t: &TestDescAndFn) -> uint {
 #[test]
 fn should_sort_failures_before_printing_them() {
     use std::io::MemWriter;
-    use std::str;
 
     let test_a = TestDesc {
         name: StaticTestName("a"),
index 41ba448754d08fd2efc491fcb41e2dcb1902472c..53e6bdc5641bb62580b6ddd25b5357387ee23d04 100644 (file)
@@ -205,28 +205,28 @@ pub fn tzset() {
 /// also called a broken-down time value.
 #[deriving(Clone, PartialEq, Show)]
 pub struct Tm {
-    /// Seconds after the minute  [0, 60]
+    /// Seconds after the minute - [0, 60]
     pub tm_sec: i32,
 
-    /// Minutes after the hour  [0, 59]
+    /// Minutes after the hour - [0, 59]
     pub tm_min: i32,
 
-    /// Hours after midnight  [0, 23]
+    /// Hours after midnight - [0, 23]
     pub tm_hour: i32,
 
-    /// Day of the month  [1, 31]
+    /// Day of the month - [1, 31]
     pub tm_mday: i32,
 
-    /// Months since January  [0, 11]
+    /// Months since January - [0, 11]
     pub tm_mon: i32,
 
     /// Years since 1900
     pub tm_year: i32,
 
-    /// Days since Sunday – [0, 6]. 0 = Sunday, 1 = Monday, …, 6 = Saturday.
+    /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
     pub tm_wday: i32,
 
-    /// Days since January 1  [0, 365]
+    /// Days since January 1 - [0, 365]
     pub tm_yday: i32,
 
     /// Daylight Saving Time flag.
@@ -240,7 +240,7 @@ pub struct Tm {
     /// for U.S. Pacific Daylight Time, the value is -7*60*60 = -25200.
     pub tm_gmtoff: i32,
 
-    /// Nanoseconds after the second  [0, 10<sup>9</sup> - 1]
+    /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
     pub tm_nsec: i32,
 }
 
index 263cf5a730a57328aa3197052ec0a622ccbc094b..2e656a5a420d340d4fee7ca83eedb3caaad23b44 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 /*!
  * Unicode-intensive string manipulations.
index aa13ae82e76d9758000a36c3daed2a11272c13c9..0e29e6215032ae104c3531a8748424bae6c0b94b 100644 (file)
@@ -520,7 +520,6 @@ mod test {
     use super::{Uuid, VariantMicrosoft, VariantNCS, VariantRFC4122,
                 Version1Mac, Version2Dce, Version3Md5, Version4Random,
                 Version5Sha1};
-    use std::str;
     use std::io::MemWriter;
     use std::rand;
 
index 1bba09755d95892bc826c558630e93803b0a4ee6..d66318a4aae089bae5c3c38ee42daaa1bd8fadb7 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit 1bba09755d95892bc826c558630e93803b0a4ee6
+Subproject commit d66318a4aae089bae5c3c38ee42daaa1bd8fadb7
index 1bd3434b46eca59bdeae275dcb79edef06acdf67..fd5c87db22cdb036c86dc2284e04360917179e47 100644 (file)
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2014-06-20.2
+2014-07-21
index fd3c4daebdb855e12552a5eae7fbd675a0c4e6b5..9af3c0c6c8c1a8eaa27cbf765e3509cee164aac3 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-lexer-test FIXME #15679
 // Microbenchmarks for various functions in std and extra
 
 #![feature(macro_rules)]
index 2b9abfbc350a64b9ef94fbe174f1cd4eaf9eb71b..a0ff7736b5c7f8ec8a15b7512b9e094dccd8d8d6 100644 (file)
@@ -16,6 +16,7 @@
 // This also serves as a pipes test, because Arcs are implemented with pipes.
 
 // no-pretty-expanded FIXME #15189
+// ignore-lexer-test FIXME #15679
 
 extern crate time;
 
index afed753f455beb2f3184dedc0466b0dfed0ae080..6512ecfb3e26063e618a6bbf4b9d2a15e4331c62 100644 (file)
@@ -16,6 +16,7 @@
 // This also serves as a pipes test, because Arcs are implemented with pipes.
 
 // no-pretty-expanded FIXME #15189
+// ignore-lexer-test FIXME #15679
 
 extern crate time;
 
index 6ec1d5395cf002ffbf013d2beb22b0aa261d9e92..bdca03490369ac200e3b5cedefe096b07d02216c 100644 (file)
@@ -10,6 +10,7 @@
 
 // Multi-language Perlin noise benchmark.
 // See https://github.com/nsf/pnoise for timings and alternative implementations.
+// ignore-lexer-test FIXME #15679
 
 use std::f32::consts::PI;
 use std::rand::{Rng, StdRng};
index 4687d66ca5391cd6087b8b7082535610877346ef..e34bfb10a719b9700da5595fd74d44bb5f82bbdb 100644 (file)
 
 extern crate libc;
 
+pub use x = extern_foo;
+extern {
+    fn extern_foo();
+}
+
 struct Foo; //~ ERROR: code is never used
 impl Foo {
     fn foo(&self) { //~ ERROR: code is never used
index 7def090edbb1173ba99e87954d69476e40d99962..ef908fdd016f994ba862146e4398f317af2039ee 100644 (file)
@@ -14,6 +14,7 @@
 // ignore-tidy-cr
 // ignore-tidy-tab
 // pp-exact:block-comment-wchar.pp
+// ignore-lexer-test FIXME #15679
 fn f() {
     fn nested() {
         /*
index 777c456335dc4237b351393cc69d432e459cb07c..06ee3715eb0440353d395dc547c5c991e408191b 100644 (file)
@@ -14,6 +14,7 @@
 // ignore-tidy-cr
 // ignore-tidy-tab
 // pp-exact:block-comment-wchar.pp
+// ignore-lexer-test FIXME #15679
 fn f() {
     fn nested() {
         /*
index ac470268d319fc7f2788fb4e9fd1a99918d80eb2..7fd7e3dbf0045a502bb7718b3726c5f68a1af131 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 
 static FOO: u8 = b'\xF0';
index e3dbaa62d353264ed5eb1b40e6bf0e49581a1f1f..a2ae91abd131a170eda6d5f1a3eeabaa550fb0fe 100644 (file)
@@ -11,7 +11,7 @@
 // aux-build:cci_class_cast.rs
 extern crate cci_class_cast;
 
-use std::to_str::ToString;
+use std::to_string::ToString;
 use cci_class_cast::kitty::cat;
 
 fn print_out(thing: Box<ToString>, expected: String) {
index 2bcf264bb1f14c20b38b2f73ec7e879bfcaa2c0f..1b2b17f99171bc6731ca5f56b00e23fd5a5d5ee0 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 
 // Tests that we can call a function bounded over a supertrait from
index e349f91a309f7f301f1a4d04d6badff2948e16f0..fabcfc5ff3347966c7e492f69871a0713615a397 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // no-pretty-expanded unnecessary unsafe block generated
+// ignore-lexer-test FIXME #15679
 
 #![feature(macro_rules, managed_boxes)]
 #![deny(warnings)]
index 418fd54cc139e8bfdf531abe5f690843bfaa3d1e..f68ba5dab8ae2756d45c25677b13057075fddbe5 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 pub fn main() {
     let x = 1i;
index e1634e44847ee4b33357ce207d0fdec8c9eff860..0efe64448c3d04f4ba27c7e35c6ef14703b8b63c 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 // Tests that match expression handles overlapped literal and range
 // properly in the presence of guard function.
diff --git a/src/test/run-pass/issue-15793.rs b/src/test/run-pass/issue-15793.rs
new file mode 100644 (file)
index 0000000..a28cb87
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum NestedEnum {
+    First,
+    Second,
+    Third
+}
+enum Enum {
+    Variant1(bool),
+    Variant2(NestedEnum)
+}
+
+#[inline(never)]
+fn foo(x: Enum) -> int {
+    match x {
+        Variant1(true) => 1,
+        Variant1(false) => 2,
+        Variant2(Second) => 3,
+        Variant2(Third) => 4,
+        Variant2(First) => 5
+    }
+}
+
+fn main() {
+    assert_eq!(foo(Variant2(Third)), 4);
+}
index 492e76552d458bad87e2ec1623fc8e127b08d9c6..974905487fe2dd09bb36c4a491dd28a53c79281a 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // ignore-test
+// ignore-lexer-test FIXME #15881
 
 // notes on this test case:
 // On Thu, Apr 18, 2013-2014 at 6:30 PM, John Clements <clements@brinckerhoff.org> wrote:
index b4807964d46dd4d8abeac5bacb13f3bb9e457ec4..c52dd5ce5e4e34aca6dbb7f81d517e4588413237 100644 (file)
@@ -8,6 +8,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 #![feature(unsafe_destructor)]
 
index aa7fa0cb5f04763173d885600e448e0659b73754..e6c816666e798247c1c506720060f7969c5dbb3f 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 
 trait Foo {
index ad8ee984217c9feeebb34d71b0589a4aec36563c..ce2f488b90c7b6adf7bde9917ce62b05cdc1b26a 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 trait U { fn f(self); }
 impl U for int { fn f(self) {} }
index 977cd08ba377082dea01b860d9d12e89ce7e0ff6..bd892465054693419c406a0e2d936d12d7a108b8 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 type FontTableTag = u32;
 
index fcb8092b7234fd7f3bed64073c18f77ef67e9bf2..511b8a9683060279c66d555a905731b1372c54a8 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 trait Fooable {
     fn yes(self);
index 5c8db524cc2edeec729b4efb9949333bace83422..421ae8e94972e8c68d6a2c9643af31a694cb6d6f 100644 (file)
@@ -16,6 +16,7 @@
 // this directory should enforce it.\r
 \r
 // ignore-pretty\r
+// ignore-lexer-test FIXME #15882\r
 \r
 /// Doc comment that ends in CRLF\r
 pub fn foo() {}\r
index d5e277b46e04fa35b8df30765b888ae08a0e3519..36c663fc847463b6c116dea8bd2e14020ca22b2b 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 
 #![forbid(non_camel_case_types)]
diff --git a/src/test/run-pass/macro-deep_expansion.rs b/src/test/run-pass/macro-deep_expansion.rs
new file mode 100644 (file)
index 0000000..f85c6f1
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(macro_rules)]
+
+macro_rules! foo2 {
+    () => {
+        "foo"
+    }
+}
+
+macro_rules! foo {
+    () => {
+        foo2!()
+    }
+}
+
+fn main() {
+    assert_eq!(concat!(foo!(), "bar"), "foobar")
+}
index 7421ae9588407f8f74fc4fb1e5e6cbab8c069919..8b782520536a0138b61df97dd447e79db6ca8975 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 pub fn main() {
     match 5u {
index ba3d89e3c7a647b9b9981dc7cfc9e6c0f8115f1e..77084836408aa199af670910c757d767d9d6156e 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 // Test that multibyte characters don't crash the compiler
 pub fn main() {
index da0c9eed9e6e86ddaebfec10bf08a648cd692134..35e863d05a177dd06262b4d4302b5f40886ed0aa 100644 (file)
Binary files a/src/test/run-pass/raw-str.rs and b/src/test/run-pass/raw-str.rs differ
index f3a730aa2b39589b823994ebd3c6ab321ff183f7..e51c94428dae3095979f0836c0d484d1d05be7d4 100644 (file)
@@ -12,7 +12,7 @@
 
 use std::collections::{ Map, MutableMap};
 use std::str::{SendStr, Owned, Slice};
-use std::to_str::ToString;
+use std::to_string::ToString;
 use self::collections::TreeMap;
 use std::option::Some;
 
index 2f78513b95cf9c7f132ca72c4d5ecb226d190b7a..bd3181842ec5dded890fa8b2a98bd7e9f777e1ac 100644 (file)
@@ -10,5 +10,7 @@
 // except according to those terms.
 
 // ignore-pretty: `expand` addes some preludes before shebang
+//
+// ignore-lexer-test FIXME #15878
 
 pub fn main() { println!("Hello World"); }
index 93c0e7f5ba5382053d6f515053a103d260bb0fa4..3e41b6d806cdc0fdec1936a5e94b6aae681ee9f3 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
 
 pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
 pub struct Floats { a: f64, b: u8, c: f64 }
index fbe40e837de5f04a1d350b134526c2ceede596f2..9b910d24bdc5fec1d872af8c4d50516f1be9e6a6 100644 (file)
@@ -7,7 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-
+//
+// ignore-lexer-test FIXME #15883
 
 
 trait to_str {
index fc4acfd5bb3c29314bf4500ee71e6a1578b1b523..ec9f666eb198dbd8db3f3adc7c416de9d0a75d85 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 pub trait Clone2 {
     /// Returns a copy of the value. The contents of owned pointers
index 1027008624a24545c906602649296e98e38c524d..270b95452187a309da9a009ca4ac3cbdb327a9c9 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 
 trait Cat {
index c6a7ab5ba49677ee8d259003e4633e89387d2d84..474632a7ffa58028e80bd8d5100ebc4013c15ac0 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15877
 
 
 trait Cat {
index f49e8f46e78e6a476f56f7a5380300789f1ed3f5..0530c8a6ab3dd48fd0b816357631e7604f07c6ec 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15879
 
 // Test syntax checks for `Sized?` syntax.
 
index 9703b55cda760855c10c5bc9fd5b07af1190a0a3..ada4da37ba11376ffaed1fc303aabee38bbffebc 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15879
 #![feature(struct_variant)]
 
 
index ccd40cb88fe08cd844f01c707d392d39c402127e..baa4e941ff097432389c287c30131ffee1533f2a 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 // This file has utf-8 BOM, it should be compiled normally without error.
 
index 557d2e5878e1dd1bf03f18786fec07e04b666ac5..a52828387bf9245e05df717655af58eb1f313a46 100644 (file)
@@ -7,7 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-
+//
+// ignore-lexer-test FIXME #15679
 // no-pretty-expanded FIXME #15189
 
 pub fn main() {
index d26a17d19f80783b89d4348604e367554e687a86..30f6f4b464e4c9d9c1567bb11bb1adca7e3d6f49 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 use std::str;
 
index ee4b2061a5dadb161ffabfe6e938393259045167..f6c4776a11cc810eb9c2845cc4063e008db8b499 100644 (file)
@@ -7,6 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+//
+// ignore-lexer-test FIXME #15679
 
 
 #![feature(non_ascii_idents)]