$(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
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
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
--- /dev/null
+# 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
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
# NOTE: Remove after reprogramming windows bots
check-fast: check-lite
+check-syntax: check-lexer
+
.PHONY: cleantmptestlogs cleantestlibs
cleantmptestlogs:
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!
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
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
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() {
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"),
+ }
}
```
`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
and then prints it back out:
```{rust,ignore}
+use std::io;
+
fn main() {
println!("Type something!");
Let's go over these chunks, one by one:
-```{rust}
+```{rust,ignore}
std::io::stdin();
```
.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:
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
" 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
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
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
" 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>();
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
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
--- /dev/null
+verify
+*.class
+*.java
+*.tokens
--- /dev/null
+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.
--- /dev/null
+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) ;
--- /dev/null
+#!/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
--- /dev/null
+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!
--- /dev/null
+// 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(..)
+ );
+ }
+}
// 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::*;
/// # Example
///
/// ```rust
-/// use collections::bitv::Bitv;
+/// use collections::Bitv;
///
/// let mut bv = Bitv::with_capacity(10, false);
///
}
}
- /// 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,
}
}
- /**
- * 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);
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);
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;
(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;
)
}
- /**
- * 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;
///
/// # 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() {
}
}
- /// 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;
}
}
- /// 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;
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);
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;
}
}
-/**
- * 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;
})
}
-/**
- * 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) {
}
/// 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);
}
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)
/// 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;
}
}
+ /// 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
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 {
}
}
+/// 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,
// <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
/// 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>;
}
/// 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.
///
// <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
/*!
// <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.
#[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);
/// 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,
/// 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> {
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()}
// <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
// <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
//!
// <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};
// <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.
//!
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 }
}
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"];
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"];
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}"];
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());
// except according to those terms.
// FIXME: this file probably shouldn't exist
+// ignore-lexer-test FIXME #15677
#![macro_escape]
// 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.
// <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.
// <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,
// except according to those terms.
// ignore-tidy-linelength
+// ignore-lexer-test FIXME #15679
use regex::{Regex, NoExpand};
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
use syntax::parse::token;
use syntax::print::pprust;
+use syntax::fold::Folder;
use rustc::plugin::Registry;
/// 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 {
//! 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;
+ }
+ }
+ }
+ }
+}
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
color: Auto,
externs: HashMap::new(),
crate_name: None,
+ alt_std_name: None,
}
}
always = always colorize output;
never = never colorize output", "auto|always|never"),
optmulti("", "extern", "Specify where an external rust library is located",
- "PATH"),
+ "NAME=PATH"),
)
}
}
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");
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 {
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
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,
};
// 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.
/// 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();
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);
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,
};
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
///
/// 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.
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(
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;
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;
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,
}
}
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 {
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
}
}
- 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(),
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(),
};
});
let mut fold = TestHarnessGenerator {
- cx: cx
+ cx: cx,
};
let res = fold.fold_crate(krate);
fold.cx.ext_cx.bt_pop();
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)
};
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,
}
}
-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);
}
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,
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,
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();
}
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;
}
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);
}
}
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;
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 {
}
}
-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),
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));
}
_ => {}
}
})
}
-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
}
}
!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)
}
}
}
// 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);
let mut bcx = bcx;
if m.len() == 0u {
if chk.is_fallible() {
- Br(bcx, chk.handle_fail());
+ chk.handle_fail(bcx);
}
return;
}
// 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,
}
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 {
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:
}
/// 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.
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,
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()
};
&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 {
})
}
-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));
use std::io;
use std::io::{File, MemWriter};
use std::gc::Gc;
+use std::collections::HashMap;
use serialize::{json, Decodable, Encodable};
use externalfiles::ExternalHtml;
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",
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()
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),
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);
/// 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");
.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");
use std::io;
use std::string::String;
+use core;
use getopts;
use testing;
}
/// 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);
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);
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 =
}));
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 {
let mut collector = Collector::new(krate.name.to_string(),
libs,
+ externs,
false);
collector.fold_crate(krate);
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);
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()
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 }
pub tests: Vec<testing::TestDescAndFn>,
names: Vec<String>,
libs: HashSet<Path>,
+ externs: core::Externs,
cnt: uint,
use_headers: bool,
current_header: Option<String>,
}
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,
};
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 {
runtest(test.as_slice(),
cratename.as_slice(),
libs,
+ externs,
should_fail,
no_run,
as_test_harness);
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>,
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;
}
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),
+ }
+ }
}
// <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::*;
// <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;
// <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;
// <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
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.
// <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)
// <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
/*!
// <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
// <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
// <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
// <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),
pub mod from_str;
pub mod num;
-pub mod to_str;
+pub mod to_string;
/* Common data structures */
// <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)]
// <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
#[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};
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 {
+++ /dev/null
-// 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());
- }
-}
--- /dev/null
+// 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());
+ }
+}
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_>;
// <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 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:
//
/// 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 {
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> {
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])
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`,
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)),
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;
}
/// 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....
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
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 => {}
}
}
}
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 {
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.
}
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,
// 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
+ }
}
}
}
// 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))
}
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()),
}
}
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();
-> 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
}
});
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!()
}
}
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: '{}!'",
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();
}
};
// 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()
}
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 =
// 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))
}
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")
};
}).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)
};
}
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: '{}!'",
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);
+ }
}
};
/// A tree-folder that performs macro expansion
pub struct MacroExpander<'a, 'b> {
- pub extsbox: SyntaxEnv,
pub cx: &'a mut ExtCtxt<'b>,
}
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();
}
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);
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());
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>,
}
}
+ /// 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
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)))
}
}
}
name_ordering: name_ordering,
nest_level: 0,
next_arg: 0,
+ literal: None,
pieces: Vec::new(),
method_statics: Vec::new(),
fmtsp: sp,
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
}
}
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() {
// <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
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
}
}
#[test]
fn should_sort_failures_before_printing_them() {
use std::io::MemWriter;
- use std::str;
let test_a = TestDesc {
name: StaticTestName("a"),
/// 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.
/// 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,
}
// <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.
use super::{Uuid, VariantMicrosoft, VariantNCS, VariantRFC4122,
Version1Mac, Version2Dce, Version3Md5, Version4Random,
Version5Sha1};
- use std::str;
use std::io::MemWriter;
use std::rand;
-Subproject commit 1bba09755d95892bc826c558630e93803b0a4ee6
+Subproject commit d66318a4aae089bae5c3c38ee42daaa1bd8fadb7
# 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
// 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)]
// 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;
// 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;
// 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};
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
// ignore-tidy-cr
// ignore-tidy-tab
// pp-exact:block-comment-wchar.pp
+// ignore-lexer-test FIXME #15679
fn f() {
fn nested() {
/*
// ignore-tidy-cr
// ignore-tidy-tab
// pp-exact:block-comment-wchar.pp
+// ignore-lexer-test FIXME #15679
fn f() {
fn nested() {
/*
// <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';
// 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) {
// <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
// except according to those terms.
// no-pretty-expanded unnecessary unsafe block generated
+// ignore-lexer-test FIXME #15679
#![feature(macro_rules, managed_boxes)]
#![deny(warnings)]
// <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;
// <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.
--- /dev/null
+// 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);
+}
// 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:
// <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)]
// <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 {
// <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) {} }
// <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;
// <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);
// 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
// <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)]
--- /dev/null
+// 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")
+}
// <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 {
// <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() {
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;
// except according to those terms.
// ignore-pretty: `expand` addes some preludes before shebang
+//
+// ignore-lexer-test FIXME #15878
pub fn main() { println!("Hello World"); }
// <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 }
// <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 {
// <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
// <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 {
// <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 {
// <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.
// <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)]
// <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.
// <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() {
// <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;
// <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)]