rollup merge of #20482: kmcallister/macro-reform
Conflicts: src/libflate/lib.rs src/libstd/lib.rs src/libstd/macros.rs src/libsyntax/feature_gate.rs src/libsyntax/parse/parser.rs src/libsyntax/show_span.rs src/test/auxiliary/macro_crate_test.rs src/test/compile-fail/lint-stability.rs src/test/run-pass/intrinsics-math.rs src/test/run-pass/tcp-connect-timeouts.rs
This commit is contained in:
commit
7975fd9cee
314 changed files with 3452 additions and 1605 deletions
|
@ -15,7 +15,14 @@
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
% The Rust Macros Guide
|
% The Rust Macros Guide
|
||||||
|
|
||||||
<div class="unstable-feature">
|
|
||||||
<b>Warning:</b> There are currently various problems with invoking macros, how
|
|
||||||
they interact with their environment, and how they are used outside of the
|
|
||||||
location in which they are defined. Macro definitions are likely to change
|
|
||||||
slightly in the future. For this reason, they are hidden behind the
|
|
||||||
<code>macro_rules</code> <a href="reference.html#compiler-features">feature
|
|
||||||
attribute</a>.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Functions are the primary tool that programmers can use to build abstractions.
|
Functions are the primary tool that programmers can use to build abstractions.
|
||||||
|
@ -46,19 +37,18 @@ lightweight custom syntax extensions, themselves defined using the
|
||||||
the pattern in the above code:
|
the pattern in the above code:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
|
||||||
# enum T { SpecialA(uint), SpecialB(uint) }
|
# enum T { SpecialA(uint), SpecialB(uint) }
|
||||||
# fn f() -> uint {
|
# fn f() -> uint {
|
||||||
# let input_1 = T::SpecialA(0);
|
# let input_1 = T::SpecialA(0);
|
||||||
# let input_2 = T::SpecialA(0);
|
# let input_2 = T::SpecialA(0);
|
||||||
macro_rules! early_return(
|
macro_rules! early_return {
|
||||||
($inp:expr $sp:path) => ( // invoke it like `(input_5 SpecialE)`
|
($inp:expr $sp:path) => ( // invoke it like `(input_5 SpecialE)`
|
||||||
match $inp {
|
match $inp {
|
||||||
$sp(x) => { return x; }
|
$sp(x) => { return x; }
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
);
|
}
|
||||||
// ...
|
// ...
|
||||||
early_return!(input_1 T::SpecialA);
|
early_return!(input_1 T::SpecialA);
|
||||||
// ...
|
// ...
|
||||||
|
@ -109,10 +99,10 @@ that could be invoked like: `my_macro!(i->(( 2+2 )))`.
|
||||||
|
|
||||||
## Invocation location
|
## Invocation location
|
||||||
|
|
||||||
A macro invocation may take the place of (and therefore expand to)
|
A macro invocation may take the place of (and therefore expand to) an
|
||||||
an expression, an item, or a statement.
|
expression, item, statement, or pattern. The Rust parser will parse the macro
|
||||||
The Rust parser will parse the macro invocation as a "placeholder"
|
invocation as a "placeholder" for whichever syntactic form is appropriate for
|
||||||
for whichever of those three nonterminals is appropriate for the location.
|
the location.
|
||||||
|
|
||||||
At expansion time, the output of the macro will be parsed as whichever of the
|
At expansion time, the output of the macro will be parsed as whichever of the
|
||||||
three nonterminals it stands in for. This means that a single macro might,
|
three nonterminals it stands in for. This means that a single macro might,
|
||||||
|
@ -166,12 +156,11 @@ separator token (a comma-separated list could be written `$(...),*`), and `+`
|
||||||
instead of `*` to mean "at least one".
|
instead of `*` to mean "at least one".
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
|
||||||
# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)}
|
# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)}
|
||||||
# fn f() -> uint {
|
# fn f() -> uint {
|
||||||
# let input_1 = T::SpecialA(0);
|
# let input_1 = T::SpecialA(0);
|
||||||
# let input_2 = T::SpecialA(0);
|
# let input_2 = T::SpecialA(0);
|
||||||
macro_rules! early_return(
|
macro_rules! early_return {
|
||||||
($inp:expr, [ $($sp:path)|+ ]) => (
|
($inp:expr, [ $($sp:path)|+ ]) => (
|
||||||
match $inp {
|
match $inp {
|
||||||
$(
|
$(
|
||||||
|
@ -180,7 +169,7 @@ macro_rules! early_return(
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
// ...
|
// ...
|
||||||
early_return!(input_1, [T::SpecialA|T::SpecialC|T::SpecialD]);
|
early_return!(input_1, [T::SpecialA|T::SpecialC|T::SpecialD]);
|
||||||
// ...
|
// ...
|
||||||
|
@ -228,7 +217,6 @@ solves the problem.
|
||||||
Now consider code like the following:
|
Now consider code like the following:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
|
||||||
# enum T1 { Good1(T2, uint), Bad1}
|
# enum T1 { Good1(T2, uint), Bad1}
|
||||||
# struct T2 { body: T3 }
|
# struct T2 { body: T3 }
|
||||||
# enum T3 { Good2(uint), Bad2}
|
# enum T3 { Good2(uint), Bad2}
|
||||||
|
@ -255,8 +243,7 @@ a match, but with a syntax that suits the problem better. The following macro
|
||||||
can solve the problem:
|
can solve the problem:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
macro_rules! biased_match {
|
||||||
macro_rules! biased_match (
|
|
||||||
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
||||||
( ($e:expr) ~ ($p:pat) else $err:stmt ;
|
( ($e:expr) ~ ($p:pat) else $err:stmt ;
|
||||||
binds $bind_res:ident
|
binds $bind_res:ident
|
||||||
|
@ -275,7 +262,7 @@ macro_rules! biased_match (
|
||||||
_ => { $err }
|
_ => { $err }
|
||||||
};
|
};
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
# enum T1 { Good1(T2, uint), Bad1}
|
# enum T1 { Good1(T2, uint), Bad1}
|
||||||
# struct T2 { body: T3 }
|
# struct T2 { body: T3 }
|
||||||
|
@ -297,13 +284,12 @@ like this, we might prefer to write a single macro invocation. The input
|
||||||
pattern we want is clear:
|
pattern we want is clear:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
# macro_rules! b(
|
# macro_rules! b {
|
||||||
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
||||||
binds $( $bind_res:ident ),*
|
binds $( $bind_res:ident ),*
|
||||||
)
|
)
|
||||||
# => (0));
|
# => (0) }
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
However, it's not possible to directly expand to nested match statements. But
|
However, it's not possible to directly expand to nested match statements. But
|
||||||
|
@ -320,24 +306,22 @@ process the semicolon-terminated lines, one-by-one. So, we want the following
|
||||||
input patterns:
|
input patterns:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
# macro_rules! b {
|
||||||
# macro_rules! b(
|
|
||||||
( binds $( $bind_res:ident ),* )
|
( binds $( $bind_res:ident ),* )
|
||||||
# => (0));
|
# => (0) }
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
...and:
|
...and:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
# macro_rules! b(
|
# macro_rules! b {
|
||||||
( ($e :expr) ~ ($p :pat) else $err :stmt ;
|
( ($e :expr) ~ ($p :pat) else $err :stmt ;
|
||||||
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
||||||
binds $( $bind_res:ident ),*
|
binds $( $bind_res:ident ),*
|
||||||
)
|
)
|
||||||
# => (0));
|
# => (0) }
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The resulting macro looks like this. Note that the separation into
|
The resulting macro looks like this. Note that the separation into
|
||||||
|
@ -345,10 +329,9 @@ The resulting macro looks like this. Note that the separation into
|
||||||
piece of syntax (the `let`) which we only want to transcribe once.
|
piece of syntax (the `let`) which we only want to transcribe once.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# #![feature(macro_rules)]
|
|
||||||
# fn main() {
|
# fn main() {
|
||||||
|
|
||||||
macro_rules! biased_match_rec (
|
macro_rules! biased_match_rec {
|
||||||
// Handle the first layer
|
// Handle the first layer
|
||||||
( ($e :expr) ~ ($p :pat) else $err :stmt ;
|
( ($e :expr) ~ ($p :pat) else $err :stmt ;
|
||||||
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
||||||
|
@ -366,10 +349,10 @@ macro_rules! biased_match_rec (
|
||||||
);
|
);
|
||||||
// Produce the requested values
|
// Produce the requested values
|
||||||
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
|
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
|
||||||
);
|
}
|
||||||
|
|
||||||
// Wrap the whole thing in a `let`.
|
// Wrap the whole thing in a `let`.
|
||||||
macro_rules! biased_match (
|
macro_rules! biased_match {
|
||||||
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
||||||
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
||||||
binds $bind_res:ident
|
binds $bind_res:ident
|
||||||
|
@ -388,7 +371,7 @@ macro_rules! biased_match (
|
||||||
binds $( $bind_res ),*
|
binds $( $bind_res ),*
|
||||||
);
|
);
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
|
|
||||||
# enum T1 { Good1(T2, uint), Bad1}
|
# enum T1 { Good1(T2, uint), Bad1}
|
||||||
|
@ -434,9 +417,7 @@ As an example, `loop` and `for-loop` labels (discussed in the lifetimes guide)
|
||||||
will not clash. The following code will print "Hello!" only once:
|
will not clash. The following code will print "Hello!" only once:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
#![feature(macro_rules)]
|
macro_rules! loop_x {
|
||||||
|
|
||||||
macro_rules! loop_x (
|
|
||||||
($e: expr) => (
|
($e: expr) => (
|
||||||
// $e will not interact with this 'x
|
// $e will not interact with this 'x
|
||||||
'x: loop {
|
'x: loop {
|
||||||
|
@ -444,7 +425,7 @@ macro_rules! loop_x (
|
||||||
$e
|
$e
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
'x: loop {
|
'x: loop {
|
||||||
|
@ -467,22 +448,30 @@ lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||||
is visible to any subsequent code in the same module, which includes the body
|
is visible to any subsequent code in the same module, which includes the body
|
||||||
of any subsequent child `mod` items.
|
of any subsequent child `mod` items.
|
||||||
|
|
||||||
If a module has the `macro_escape` attribute, its macros are also visible in
|
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||||
its parent module after the child's `mod` item. If the parent also has
|
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||||
`macro_escape` then the macros will be visible in the grandparent after the
|
then the macros will be visible in the grandparent after the parent's `mod`
|
||||||
parent's `mod` item, and so forth.
|
item, and so forth.
|
||||||
|
|
||||||
Independent of `macro_escape`, the `macro_export` attribute controls visibility
|
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||||
between crates. Any `macro_rules!` definition with the `macro_export`
|
it controls which macros are loaded from the external crate, e.g.
|
||||||
attribute will be visible to other crates that have loaded this crate with
|
|
||||||
`phase(plugin)`. There is currently no way for the importing crate to control
|
```rust,ignore
|
||||||
which macros are imported.
|
#[macro_use(foo, bar)]
|
||||||
|
extern crate baz;
|
||||||
|
```
|
||||||
|
|
||||||
|
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||||
|
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||||
|
defined with the `#[macro_export]` attribute may be loaded.
|
||||||
|
|
||||||
|
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||||
|
as well.
|
||||||
|
|
||||||
An example:
|
An example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(macro_rules)]
|
macro_rules! m1 { () => (()) }
|
||||||
macro_rules! m1 (() => (()));
|
|
||||||
|
|
||||||
// visible here: m1
|
// visible here: m1
|
||||||
|
|
||||||
|
@ -490,22 +479,22 @@ mod foo {
|
||||||
// visible here: m1
|
// visible here: m1
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! m2 (() => (()));
|
macro_rules! m2 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1, m2
|
// visible here: m1, m2
|
||||||
}
|
}
|
||||||
|
|
||||||
// visible here: m1
|
// visible here: m1
|
||||||
|
|
||||||
macro_rules! m3 (() => (()));
|
macro_rules! m3 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1, m3
|
// visible here: m1, m3
|
||||||
|
|
||||||
#[macro_escape]
|
#[macro_use]
|
||||||
mod bar {
|
mod bar {
|
||||||
// visible here: m1, m3
|
// visible here: m1, m3
|
||||||
|
|
||||||
macro_rules! m4 (() => (()));
|
macro_rules! m4 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1, m3, m4
|
// visible here: m1, m3, m4
|
||||||
}
|
}
|
||||||
|
@ -514,8 +503,58 @@ mod bar {
|
||||||
# fn main() { }
|
# fn main() { }
|
||||||
```
|
```
|
||||||
|
|
||||||
When this library is loaded with `#[phase(plugin)] extern crate`, only `m2`
|
When this library is loaded with `#[use_macros] extern crate`, only `m2` will
|
||||||
will be imported.
|
be imported.
|
||||||
|
|
||||||
|
The Rust Reference has a [listing of macro-related
|
||||||
|
attributes](reference.html#macro--and-plugin-related-attributes).
|
||||||
|
|
||||||
|
# The variable `$crate`
|
||||||
|
|
||||||
|
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||||
|
`mylib` defines
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub fn increment(x: uint) -> uint {
|
||||||
|
x + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! inc_a {
|
||||||
|
($x:expr) => ( ::increment($x) )
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! inc_b {
|
||||||
|
($x:expr) => ( ::mylib::increment($x) )
|
||||||
|
}
|
||||||
|
# fn main() { }
|
||||||
|
```
|
||||||
|
|
||||||
|
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||||
|
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||||
|
another name.
|
||||||
|
|
||||||
|
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||||
|
provide a simple workaround for this problem. Within a macro imported from a
|
||||||
|
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||||
|
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||||
|
will expand to nothing. This means we can write
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! inc {
|
||||||
|
($x:expr) => ( $crate::increment($x) )
|
||||||
|
}
|
||||||
|
# fn main() { }
|
||||||
|
```
|
||||||
|
|
||||||
|
to define a single macro that works both inside and outside our library. The
|
||||||
|
function name will expand to either `::increment` or `::mylib::increment`.
|
||||||
|
|
||||||
|
To keep this system simple and correct, `#[macro_use] extern crate ...` may
|
||||||
|
only appear at the root of your crate, not inside `mod`. This ensures that
|
||||||
|
`$crate` is a single identifier.
|
||||||
|
|
||||||
# A final note
|
# A final note
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,14 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc.
|
||||||
|
|
||||||
A plugin is a dynamic library crate with a designated "registrar" function that
|
A plugin is a dynamic library crate with a designated "registrar" function that
|
||||||
registers extensions with `rustc`. Other crates can use these extensions by
|
registers extensions with `rustc`. Other crates can use these extensions by
|
||||||
loading the plugin crate with `#[phase(plugin)] extern crate`. See the
|
loading the plugin crate with `#[plugin] extern crate`. See the
|
||||||
[`rustc::plugin`](rustc/plugin/index.html) documentation for more about the
|
[`rustc::plugin`](rustc/plugin/index.html) documentation for more about the
|
||||||
mechanics of defining and loading a plugin.
|
mechanics of defining and loading a plugin.
|
||||||
|
|
||||||
|
Arguments passed as `#[plugin=...]` or `#[plugin(...)]` are not interpreted by
|
||||||
|
rustc itself. They are provided to the plugin through the `Registry`'s [`args`
|
||||||
|
method](rustc/plugin/registry/struct.Registry.html#method.args).
|
||||||
|
|
||||||
# Syntax extensions
|
# Syntax extensions
|
||||||
|
|
||||||
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
||||||
|
@ -105,10 +109,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
Then we can use `rn!()` like any other macro:
|
Then we can use `rn!()` like any other macro:
|
||||||
|
|
||||||
```ignore
|
```ignore
|
||||||
#![feature(phase)]
|
#![feature(plugin)]
|
||||||
|
|
||||||
#[phase(plugin)]
|
#[plugin] extern crate roman_numerals;
|
||||||
extern crate roman_numerals;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(rn!(MMXV), 2015);
|
assert_eq!(rn!(MMXV), 2015);
|
||||||
|
@ -217,8 +220,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
Then code like
|
Then code like
|
||||||
|
|
||||||
```ignore
|
```ignore
|
||||||
#[phase(plugin)]
|
#[plugin] extern crate lint_plugin_test;
|
||||||
extern crate lint_plugin_test;
|
|
||||||
|
|
||||||
fn lintme() { }
|
fn lintme() { }
|
||||||
```
|
```
|
||||||
|
|
|
@ -193,12 +193,12 @@ grammar as double-quoted strings. Other tokens have exact rules given.
|
||||||
| break | const | continue | crate | do |
|
| break | const | continue | crate | do |
|
||||||
| else | enum | extern | false | final |
|
| else | enum | extern | false | final |
|
||||||
| fn | for | if | impl | in |
|
| fn | for | if | impl | in |
|
||||||
| let | loop | match | mod | move |
|
| let | loop | macro | match | mod |
|
||||||
| mut | offsetof | override | priv | pub |
|
| move | mut | offsetof | override | priv |
|
||||||
| pure | ref | return | sizeof | static |
|
| pub | pure | ref | return | sizeof |
|
||||||
| self | struct | super | true | trait |
|
| static | self | struct | super | true |
|
||||||
| type | typeof | unsafe | unsized | use |
|
| trait | type | typeof | unsafe | unsized |
|
||||||
| virtual | where | while | yield |
|
| use | virtual | where | while | yield |
|
||||||
|
|
||||||
|
|
||||||
Each of these keywords has special meaning in its grammar, and all of them are
|
Each of these keywords has special meaning in its grammar, and all of them are
|
||||||
|
@ -668,9 +668,11 @@ transcriber : '(' transcriber * ')' | '[' transcriber * ']'
|
||||||
| non_special_token ;
|
| non_special_token ;
|
||||||
```
|
```
|
||||||
|
|
||||||
User-defined syntax extensions are called "macros", and the `macro_rules`
|
`macro_rules` allows users to define syntax extension in a declarative way. We
|
||||||
syntax extension defines them. Currently, user-defined macros can expand to
|
call such extensions "macros by example" or simply "macros" — to be distinguished
|
||||||
expressions, statements, items, or patterns.
|
from the "procedural macros" defined in [compiler plugins][plugin].
|
||||||
|
|
||||||
|
Currently, macros can expand to expressions, statements, items, or patterns.
|
||||||
|
|
||||||
(A `sep_token` is any token other than `*` and `+`. A `non_special_token` is
|
(A `sep_token` is any token other than `*` and `+`. A `non_special_token` is
|
||||||
any token other than a delimiter or `$`.)
|
any token other than a delimiter or `$`.)
|
||||||
|
@ -2002,8 +2004,6 @@ type int8_t = i8;
|
||||||
|
|
||||||
### Module-only attributes
|
### Module-only attributes
|
||||||
|
|
||||||
- `macro_escape` - macros defined in this module will be visible in the
|
|
||||||
module's parent, after this module has been included.
|
|
||||||
- `no_implicit_prelude` - disable injecting `use std::prelude::*` in this
|
- `no_implicit_prelude` - disable injecting `use std::prelude::*` in this
|
||||||
module.
|
module.
|
||||||
- `path` - specifies the file to load the module from. `#[path="foo.rs"] mod
|
- `path` - specifies the file to load the module from. `#[path="foo.rs"] mod
|
||||||
|
@ -2066,23 +2066,43 @@ On `struct`s:
|
||||||
remove any padding between fields (note that this is very fragile and may
|
remove any padding between fields (note that this is very fragile and may
|
||||||
break platforms which require aligned access).
|
break platforms which require aligned access).
|
||||||
|
|
||||||
|
### Macro- and plugin-related attributes
|
||||||
|
|
||||||
|
- `macro_use` on a `mod` — macros defined in this module will be visible in the
|
||||||
|
module's parent, after this module has been included.
|
||||||
|
|
||||||
|
- `macro_use` on an `extern crate` — load macros from this crate. An optional
|
||||||
|
list of names `#[macro_use(foo, bar)]` restricts the import to just those
|
||||||
|
macros named. The `extern crate` must appear at the crate root, not inside
|
||||||
|
`mod`, which ensures proper function of the [`$crate` macro
|
||||||
|
variable](guide-macros.html#the-variable-$crate).
|
||||||
|
|
||||||
|
- `macro_reexport` on an `extern crate` — re-export the named macros.
|
||||||
|
|
||||||
|
- `macro_export` - export a macro for cross-crate usage.
|
||||||
|
|
||||||
|
- `plugin` on an `extern crate` — load this crate as a [compiler
|
||||||
|
plugin][plugin]. The `plugin` feature gate is required. Any arguments to
|
||||||
|
the attribute, e.g. `#[plugin=...]` or `#[plugin(...)]`, are provided to the
|
||||||
|
plugin.
|
||||||
|
|
||||||
|
- `no_link` on an `extern crate` — even if we load this crate for macros or
|
||||||
|
compiler plugins, don't link it into the output.
|
||||||
|
|
||||||
|
See the [macros guide](guide-macros.html#scoping-and-macro-import/export) for
|
||||||
|
more information on macro scope.
|
||||||
|
|
||||||
|
|
||||||
### Miscellaneous attributes
|
### Miscellaneous attributes
|
||||||
|
|
||||||
- `export_name` - on statics and functions, this determines the name of the
|
- `export_name` - on statics and functions, this determines the name of the
|
||||||
exported symbol.
|
exported symbol.
|
||||||
- `link_section` - on statics and functions, this specifies the section of the
|
- `link_section` - on statics and functions, this specifies the section of the
|
||||||
object file that this item's contents will be placed into.
|
object file that this item's contents will be placed into.
|
||||||
- `macro_export` - export a macro for cross-crate usage.
|
|
||||||
- `no_mangle` - on any item, do not apply the standard name mangling. Set the
|
- `no_mangle` - on any item, do not apply the standard name mangling. Set the
|
||||||
symbol for this item to its identifier.
|
symbol for this item to its identifier.
|
||||||
- `packed` - on structs or enums, eliminate any padding that would be used to
|
- `packed` - on structs or enums, eliminate any padding that would be used to
|
||||||
align fields.
|
align fields.
|
||||||
- `phase` - on `extern crate` statements, allows specifying which "phase" of
|
|
||||||
compilation the crate should be loaded for. Currently, there are two
|
|
||||||
choices: `link` and `plugin`. `link` is the default. `plugin` will [load the
|
|
||||||
crate at compile-time][plugin] and use any syntax extensions or lints that the crate
|
|
||||||
defines. They can both be specified, `#[phase(link, plugin)]` to use a crate
|
|
||||||
both at runtime and compiletime.
|
|
||||||
- `simd` - on certain tuple structs, derive the arithmetic operators, which
|
- `simd` - on certain tuple structs, derive the arithmetic operators, which
|
||||||
lower to the target's SIMD instructions, if any; the `simd` feature gate
|
lower to the target's SIMD instructions, if any; the `simd` feature gate
|
||||||
is necessary to use this attribute.
|
is necessary to use this attribute.
|
||||||
|
@ -2569,15 +2589,6 @@ The currently implemented features of the reference compiler are:
|
||||||
* `log_syntax` - Allows use of the `log_syntax` macro attribute, which is a
|
* `log_syntax` - Allows use of the `log_syntax` macro attribute, which is a
|
||||||
nasty hack that will certainly be removed.
|
nasty hack that will certainly be removed.
|
||||||
|
|
||||||
* `macro_rules` - The definition of new macros. This does not encompass
|
|
||||||
macro-invocation, that is always enabled by default, this
|
|
||||||
only covers the definition of new macros. There are currently
|
|
||||||
various problems with invoking macros, how they interact with
|
|
||||||
their environment, and possibly how they are used outside of
|
|
||||||
location in which they are defined. Macro definitions are
|
|
||||||
likely to change slightly in the future, so they are
|
|
||||||
currently hidden behind this feature.
|
|
||||||
|
|
||||||
* `non_ascii_idents` - The compiler supports the use of non-ascii identifiers,
|
* `non_ascii_idents` - The compiler supports the use of non-ascii identifiers,
|
||||||
but the implementation is a little rough around the
|
but the implementation is a little rough around the
|
||||||
edges, so this can be seen as an experimental feature
|
edges, so this can be seen as an experimental feature
|
||||||
|
@ -2588,15 +2599,10 @@ The currently implemented features of the reference compiler are:
|
||||||
closure as `once` is unlikely to be supported going forward. So
|
closure as `once` is unlikely to be supported going forward. So
|
||||||
they are hidden behind this feature until they are to be removed.
|
they are hidden behind this feature until they are to be removed.
|
||||||
|
|
||||||
* `phase` - Usage of the `#[phase]` attribute allows loading compiler plugins
|
* `plugin` - Usage of [compiler plugins][plugin] for custom lints or syntax extensions.
|
||||||
for custom lints or syntax extensions. The implementation is
|
These depend on compiler internals and are subject to change.
|
||||||
considered unwholesome and in need of overhaul, and it is not clear
|
|
||||||
what they will look like moving forward.
|
|
||||||
|
|
||||||
* `plugin_registrar` - Indicates that a crate has [compiler plugins][plugin] that it
|
* `plugin_registrar` - Indicates that a crate provides [compiler plugins][plugin].
|
||||||
wants to load. As with `phase`, the implementation is
|
|
||||||
in need of an overhaul, and it is not clear that plugins
|
|
||||||
defined using this will continue to work.
|
|
||||||
|
|
||||||
* `quote` - Allows use of the `quote_*!` family of macros, which are
|
* `quote` - Allows use of the `quote_*!` family of macros, which are
|
||||||
implemented very poorly and will likely change significantly
|
implemented very poorly and will likely change significantly
|
||||||
|
|
|
@ -56,7 +56,7 @@ syn match rustMacroRepeatCount ".\?[*+]" contained
|
||||||
syn match rustMacroVariable "$\w\+"
|
syn match rustMacroVariable "$\w\+"
|
||||||
|
|
||||||
" Reserved (but not yet used) keywords {{{2
|
" Reserved (but not yet used) keywords {{{2
|
||||||
syn keyword rustReservedKeyword alignof be do offsetof priv pure sizeof typeof unsized yield abstract final override
|
syn keyword rustReservedKeyword alignof be do offsetof priv pure sizeof typeof unsized yield abstract final override macro
|
||||||
|
|
||||||
" Built-in types {{{2
|
" Built-in types {{{2
|
||||||
syn keyword rustType int uint float char bool u8 u16 u32 u64 f32
|
syn keyword rustType int uint float char bool u8 u16 u32 u64 f32
|
||||||
|
|
|
@ -8,15 +8,14 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(globs, phase, macro_rules)]
|
#![feature(globs, plugin)]
|
||||||
|
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
|
|
||||||
#[phase(link)]
|
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
#[phase(link, plugin)]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -269,7 +268,7 @@ fn main() {
|
||||||
assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
|
assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
|
||||||
antlr_tok);
|
antlr_tok);
|
||||||
|
|
||||||
macro_rules! matches (
|
macro_rules! matches {
|
||||||
( $($x:pat),+ ) => (
|
( $($x:pat),+ ) => (
|
||||||
match rustc_tok.tok {
|
match rustc_tok.tok {
|
||||||
$($x => match antlr_tok.tok {
|
$($x => match antlr_tok.tok {
|
||||||
|
@ -285,7 +284,7 @@ fn main() {
|
||||||
ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
|
ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
matches!(
|
matches!(
|
||||||
token::Literal(token::Byte(..), _),
|
token::Literal(token::Byte(..), _),
|
||||||
|
|
|
@ -68,14 +68,33 @@
|
||||||
#![feature(lang_items, phase, unsafe_destructor, default_type_params, old_orphan_check)]
|
#![feature(lang_items, phase, unsafe_destructor, default_type_params, old_orphan_check)]
|
||||||
#![feature(associated_types)]
|
#![feature(associated_types)]
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)]
|
#[phase(plugin, link)]
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
// Allow testing this library
|
// Allow testing this library
|
||||||
|
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate std;
|
#[cfg(all(test, stage0))]
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
#[phase(plugin, link)]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[cfg(all(test, stage0))]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
// Heaps provided for low-level allocation strategies
|
// Heaps provided for low-level allocation strategies
|
||||||
|
|
||||||
|
|
|
@ -29,15 +29,34 @@
|
||||||
#![feature(associated_types)]
|
#![feature(associated_types)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[phase(plugin, link)] extern crate core;
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
extern crate unicode;
|
extern crate unicode;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[cfg(test)] extern crate test;
|
#[cfg(test)] extern crate test;
|
||||||
|
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate std;
|
#[cfg(all(test, stage0))]
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
#[phase(plugin, link)]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[cfg(all(test, stage0))]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
pub use binary_heap::BinaryHeap;
|
pub use binary_heap::BinaryHeap;
|
||||||
pub use bitv::Bitv;
|
pub use bitv::Bitv;
|
||||||
|
@ -51,6 +70,11 @@ pub use string::String;
|
||||||
pub use vec::Vec;
|
pub use vec::Vec;
|
||||||
pub use vec_map::VecMap;
|
pub use vec_map::VecMap;
|
||||||
|
|
||||||
|
// Needed for the vec! macro
|
||||||
|
pub use alloc::boxed;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub mod binary_heap;
|
pub mod binary_heap;
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
/// Creates a `std::vec::Vec` containing the arguments.
|
/// Creates a `std::vec::Vec` containing the arguments.
|
||||||
|
// NOTE: remove after the next snapshot
|
||||||
|
#[cfg(stage0)]
|
||||||
macro_rules! vec {
|
macro_rules! vec {
|
||||||
($($e:expr),*) => ({
|
($($e:expr),*) => ({
|
||||||
// leading _ to allow empty construction without a warning.
|
// leading _ to allow empty construction without a warning.
|
||||||
|
@ -21,3 +21,13 @@ macro_rules! vec {
|
||||||
($($e:expr),+,) => (vec!($($e),+))
|
($($e:expr),+,) => (vec!($($e),+))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a `Vec` containing the arguments.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! vec {
|
||||||
|
($($x:expr),*) => ({
|
||||||
|
let xs: $crate::boxed::Box<[_]> = box [$($x),*];
|
||||||
|
$crate::slice::SliceExt::into_vec(xs)
|
||||||
|
});
|
||||||
|
($($x:expr,)*) => (vec![$($x),*])
|
||||||
|
}
|
||||||
|
|
|
@ -2598,13 +2598,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_show() {
|
fn test_show() {
|
||||||
macro_rules! test_show_vec(
|
macro_rules! test_show_vec {
|
||||||
($x:expr, $x_str:expr) => ({
|
($x:expr, $x_str:expr) => ({
|
||||||
let (x, x_str) = ($x, $x_str);
|
let (x, x_str) = ($x, $x_str);
|
||||||
assert_eq!(format!("{}", x), x_str);
|
assert_eq!(format!("{}", x), x_str);
|
||||||
assert_eq!(format!("{}", x.as_slice()), x_str);
|
assert_eq!(format!("{}", x.as_slice()), x_str);
|
||||||
})
|
})
|
||||||
);
|
}
|
||||||
let empty: Vec<int> = vec![];
|
let empty: Vec<int> = vec![];
|
||||||
test_show_vec!(empty, "[]");
|
test_show_vec!(empty, "[]");
|
||||||
test_show_vec!(vec![1i], "[1]");
|
test_show_vec!(vec![1i], "[1]");
|
||||||
|
@ -2624,12 +2624,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vec_default() {
|
fn test_vec_default() {
|
||||||
macro_rules! t (
|
macro_rules! t {
|
||||||
($ty:ty) => {{
|
($ty:ty) => {{
|
||||||
let v: $ty = Default::default();
|
let v: $ty = Default::default();
|
||||||
assert!(v.is_empty());
|
assert!(v.is_empty());
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(&[int]);
|
t!(&[int]);
|
||||||
t!(Vec<int>);
|
t!(Vec<int>);
|
||||||
|
|
|
@ -1846,7 +1846,9 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_utf16() {
|
fn test_is_utf16() {
|
||||||
use unicode::str::is_utf16;
|
use unicode::str::is_utf16;
|
||||||
macro_rules! pos ( ($($e:expr),*) => { { $(assert!(is_utf16($e));)* } });
|
macro_rules! pos {
|
||||||
|
($($e:expr),*) => { { $(assert!(is_utf16($e));)* } }
|
||||||
|
}
|
||||||
|
|
||||||
// non-surrogates
|
// non-surrogates
|
||||||
pos!(&[0x0000],
|
pos!(&[0x0000],
|
||||||
|
@ -1866,7 +1868,9 @@ mod tests {
|
||||||
&[0x0067, 0xd8ff, 0xddb7, 0x000f, 0xd900, 0xdc80]);
|
&[0x0067, 0xd8ff, 0xddb7, 0x000f, 0xd900, 0xdc80]);
|
||||||
|
|
||||||
// negative tests
|
// negative tests
|
||||||
macro_rules! neg ( ($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } });
|
macro_rules! neg {
|
||||||
|
($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } }
|
||||||
|
}
|
||||||
|
|
||||||
neg!(
|
neg!(
|
||||||
// surrogate + regular unit
|
// surrogate + regular unit
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl String {
|
||||||
let byte = unsafe_get(v, i);
|
let byte = unsafe_get(v, i);
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
macro_rules! error(() => ({
|
macro_rules! error { () => ({
|
||||||
unsafe {
|
unsafe {
|
||||||
if subseqidx != i_ {
|
if subseqidx != i_ {
|
||||||
res.as_mut_vec().push_all(v[subseqidx..i_]);
|
res.as_mut_vec().push_all(v[subseqidx..i_]);
|
||||||
|
@ -190,7 +190,7 @@ impl String {
|
||||||
subseqidx = i;
|
subseqidx = i;
|
||||||
res.as_mut_vec().push_all(REPLACEMENT);
|
res.as_mut_vec().push_all(REPLACEMENT);
|
||||||
}
|
}
|
||||||
}));
|
})}
|
||||||
|
|
||||||
if byte < 128u8 {
|
if byte < 128u8 {
|
||||||
// subseqidx handles this
|
// subseqidx handles this
|
||||||
|
|
|
@ -20,12 +20,15 @@ use mem;
|
||||||
use option::Option;
|
use option::Option;
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
use ops::{Deref, FnOnce};
|
use ops::{Deref, FnOnce};
|
||||||
use result::Result::{Ok, Err};
|
use result::Result::Ok;
|
||||||
use result;
|
use result;
|
||||||
use slice::SliceExt;
|
use slice::SliceExt;
|
||||||
use slice;
|
use slice;
|
||||||
use str::{self, StrExt, Utf8Error};
|
use str::{self, StrExt, Utf8Error};
|
||||||
|
|
||||||
|
// NOTE: for old macros; remove after the next snapshot
|
||||||
|
#[cfg(stage0)] use result::Result::Err;
|
||||||
|
|
||||||
pub use self::num::radix;
|
pub use self::num::radix;
|
||||||
pub use self::num::Radix;
|
pub use self::num::Radix;
|
||||||
pub use self::num::RadixFmt;
|
pub use self::num::RadixFmt;
|
||||||
|
|
|
@ -62,11 +62,24 @@
|
||||||
#![feature(default_type_params, unboxed_closures, associated_types)]
|
#![feature(default_type_params, unboxed_closures, associated_types)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
#[path = "num/float_macros.rs"] mod float_macros;
|
#[path = "num/float_macros.rs"]
|
||||||
#[path = "num/int_macros.rs"] mod int_macros;
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
#[path = "num/uint_macros.rs"] mod uint_macros;
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
mod float_macros;
|
||||||
|
|
||||||
|
#[path = "num/int_macros.rs"]
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
mod int_macros;
|
||||||
|
|
||||||
|
#[path = "num/uint_macros.rs"]
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
mod uint_macros;
|
||||||
|
|
||||||
#[path = "num/int.rs"] pub mod int;
|
#[path = "num/int.rs"] pub mod int;
|
||||||
#[path = "num/i8.rs"] pub mod i8;
|
#[path = "num/i8.rs"] pub mod i8;
|
||||||
|
@ -130,6 +143,7 @@ mod array;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
mod core {
|
mod core {
|
||||||
pub use panicking;
|
pub use panicking;
|
||||||
|
pub use fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
/// Entry point of task panic, for details, see std::macros
|
/// Entry point of task panic, for details, see std::macros
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! panic {
|
macro_rules! panic {
|
||||||
|
@ -30,7 +28,26 @@ macro_rules! panic {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runtime assertion, for details see std::macros
|
/// Ensure that a boolean expression is `true` at runtime.
|
||||||
|
///
|
||||||
|
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||||
|
/// evaluated to `true` at runtime.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // the panic message for these assertions is the stringified value of the
|
||||||
|
/// // expression given.
|
||||||
|
/// assert!(true);
|
||||||
|
/// # fn some_computation() -> bool { true }
|
||||||
|
/// assert!(some_computation());
|
||||||
|
///
|
||||||
|
/// // assert with a custom message
|
||||||
|
/// # let x = true;
|
||||||
|
/// assert!(x, "x wasn't true!");
|
||||||
|
/// # let a = 3i; let b = 27i;
|
||||||
|
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert {
|
macro_rules! assert {
|
||||||
($cond:expr) => (
|
($cond:expr) => (
|
||||||
|
@ -38,61 +55,197 @@ macro_rules! assert {
|
||||||
panic!(concat!("assertion failed: ", stringify!($cond)))
|
panic!(concat!("assertion failed: ", stringify!($cond)))
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
($cond:expr, $($arg:tt)*) => (
|
($cond:expr, $($arg:expr),+) => (
|
||||||
if !$cond {
|
if !$cond {
|
||||||
panic!($($arg)*)
|
panic!($($arg),+)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runtime assertion for equality, for details see std::macros
|
/// Asserts that two expressions are equal to each other, testing equality in
|
||||||
|
/// both directions.
|
||||||
|
///
|
||||||
|
/// On panic, this macro will print the values of the expressions.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let a = 3i;
|
||||||
|
/// let b = 1i + 2i;
|
||||||
|
/// assert_eq!(a, b);
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_eq {
|
macro_rules! assert_eq {
|
||||||
($cond1:expr, $cond2:expr) => ({
|
($left:expr , $right:expr) => ({
|
||||||
let c1 = $cond1;
|
match (&($left), &($right)) {
|
||||||
let c2 = $cond2;
|
(left_val, right_val) => {
|
||||||
if c1 != c2 || c2 != c1 {
|
// check both directions of equality....
|
||||||
panic!("expressions not equal, left: {}, right: {}", c1, c2);
|
if !((*left_val == *right_val) &&
|
||||||
|
(*right_val == *left_val)) {
|
||||||
|
panic!("assertion failed: `(left == right) && (right == left)` \
|
||||||
|
(left: `{}`, right: `{}`)", *left_val, *right_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runtime assertion for equality, only without `--cfg ndebug`
|
/// Ensure that a boolean expression is `true` at runtime.
|
||||||
#[macro_export]
|
///
|
||||||
macro_rules! debug_assert_eq {
|
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||||
($($a:tt)*) => ({
|
/// evaluated to `true` at runtime.
|
||||||
if cfg!(not(ndebug)) {
|
///
|
||||||
assert_eq!($($a)*);
|
/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing
|
||||||
}
|
/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for
|
||||||
})
|
/// checks that are too expensive to be present in a release build but may be
|
||||||
}
|
/// helpful during development.
|
||||||
|
///
|
||||||
/// Runtime assertion, disableable at compile time with `--cfg ndebug`
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // the panic message for these assertions is the stringified value of the
|
||||||
|
/// // expression given.
|
||||||
|
/// debug_assert!(true);
|
||||||
|
/// # fn some_expensive_computation() -> bool { true }
|
||||||
|
/// debug_assert!(some_expensive_computation());
|
||||||
|
///
|
||||||
|
/// // assert with a custom message
|
||||||
|
/// # let x = true;
|
||||||
|
/// debug_assert!(x, "x wasn't true!");
|
||||||
|
/// # let a = 3i; let b = 27i;
|
||||||
|
/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b);
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! debug_assert {
|
macro_rules! debug_assert {
|
||||||
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
|
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Short circuiting evaluation on Err
|
/// Asserts that two expressions are equal to each other, testing equality in
|
||||||
|
/// both directions.
|
||||||
|
///
|
||||||
|
/// On panic, this macro will print the values of the expressions.
|
||||||
|
///
|
||||||
|
/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by
|
||||||
|
/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!`
|
||||||
|
/// useful for checks that are too expensive to be present in a release build
|
||||||
|
/// but may be helpful during development.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let a = 3i;
|
||||||
|
/// let b = 1i + 2i;
|
||||||
|
/// debug_assert_eq!(a, b);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug_assert_eq {
|
||||||
|
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! try {
|
macro_rules! try {
|
||||||
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writing a formatted string into a writer
|
/// Short circuiting evaluation on Err
|
||||||
|
///
|
||||||
|
/// `libstd` contains a more general `try!` macro that uses `FromError`.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! try {
|
||||||
|
($e:expr) => ({
|
||||||
|
use $crate::result::Result::{Ok, Err};
|
||||||
|
|
||||||
|
match $e {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
|
||||||
|
/// See `std::fmt` for more information.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![allow(unused_must_use)]
|
||||||
|
///
|
||||||
|
/// let mut w = Vec::new();
|
||||||
|
/// write!(&mut w, "test");
|
||||||
|
/// write!(&mut w, "formatted {}", "arguments");
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! write {
|
macro_rules! write {
|
||||||
($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
|
($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writing a formatted string plus a newline into a writer
|
/// Equivalent to the `write!` macro, except that a newline is appended after
|
||||||
|
/// the message is written.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
#[stable]
|
||||||
macro_rules! writeln {
|
macro_rules! writeln {
|
||||||
($dst:expr, $fmt:expr $($arg:tt)*) => (
|
($dst:expr, $fmt:expr $($arg:tt)*) => (
|
||||||
write!($dst, concat!($fmt, "\n") $($arg)*)
|
write!($dst, concat!($fmt, "\n") $($arg)*)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A utility macro for indicating unreachable code.
|
||||||
|
///
|
||||||
|
/// This is useful any time that the compiler can't determine that some code is unreachable. For
|
||||||
|
/// example:
|
||||||
|
///
|
||||||
|
/// * Match arms with guard conditions.
|
||||||
|
/// * Loops that dynamically terminate.
|
||||||
|
/// * Iterators that dynamically terminate.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This will always panic.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Match arms:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn foo(x: Option<int>) {
|
||||||
|
/// match x {
|
||||||
|
/// Some(n) if n >= 0 => println!("Some(Non-negative)"),
|
||||||
|
/// Some(n) if n < 0 => println!("Some(Negative)"),
|
||||||
|
/// Some(_) => unreachable!(), // compile error if commented out
|
||||||
|
/// None => println!("None")
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Iterators:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
|
||||||
|
/// for i in std::iter::count(0_u32, 1) {
|
||||||
|
/// if 3*i < i { panic!("u32 overflow"); }
|
||||||
|
/// if x < 3*i { return i-1; }
|
||||||
|
/// }
|
||||||
|
/// unreachable!();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! unreachable { () => (panic!("unreachable code")) }
|
macro_rules! unreachable {
|
||||||
|
() => ({
|
||||||
|
panic!("internal error: entered unreachable code")
|
||||||
|
});
|
||||||
|
($msg:expr) => ({
|
||||||
|
unreachable!("{}", $msg)
|
||||||
|
});
|
||||||
|
($fmt:expr, $($arg:tt)*) => ({
|
||||||
|
panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A standardised placeholder for marking unfinished code. It panics with the
|
||||||
|
/// message `"not yet implemented"` when executed.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unimplemented {
|
||||||
|
() => (panic!("not yet implemented"))
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
|
|
||||||
macro_rules! assert_approx_eq {
|
macro_rules! assert_approx_eq {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
|
|
||||||
macro_rules! int_module { ($T:ty, $bits:expr) => (
|
macro_rules! int_module { ($T:ty, $bits:expr) => (
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
|
|
||||||
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (
|
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (
|
||||||
|
|
|
@ -220,9 +220,9 @@
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #![feature(macro_rules)]
|
//! # #![feature(macro_rules)]
|
||||||
//! macro_rules! try(
|
//! macro_rules! try {
|
||||||
//! ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
//! ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
||||||
//! );
|
//! }
|
||||||
//! # fn main() { }
|
//! # fn main() { }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -964,17 +964,18 @@ fn run_utf8_validation_iterator(iter: &mut slice::Iter<u8>)
|
||||||
let old = *iter;
|
let old = *iter;
|
||||||
|
|
||||||
// restore the iterator we had at the start of this codepoint.
|
// restore the iterator we had at the start of this codepoint.
|
||||||
macro_rules! err (() => { {
|
macro_rules! err { () => {{
|
||||||
*iter = old;
|
*iter = old;
|
||||||
return Err(Utf8Error::InvalidByte(whole.len() - iter.as_slice().len()))
|
return Err(Utf8Error::InvalidByte(whole.len() - iter.as_slice().len()))
|
||||||
} });
|
}}}
|
||||||
macro_rules! next ( () => {
|
|
||||||
|
macro_rules! next { () => {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(a) => *a,
|
Some(a) => *a,
|
||||||
// we needed data, but there was none: error!
|
// we needed data, but there was none: error!
|
||||||
None => return Err(Utf8Error::TooShort),
|
None => return Err(Utf8Error::TooShort),
|
||||||
}
|
}
|
||||||
});
|
}}
|
||||||
|
|
||||||
let first = match iter.next() {
|
let first = match iter.next() {
|
||||||
Some(&b) => b,
|
Some(&b) => b,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
#![feature(globs, unsafe_destructor, macro_rules, slicing_syntax, default_type_params)]
|
#![feature(globs, unsafe_destructor, slicing_syntax, default_type_params)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
macro_rules! int_module { ($T:ty, $T_i:ident) => (
|
||||||
|
|
||||||
macro_rules! int_module (($T:ty, $T_i:ident) => (
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::$T_i::*;
|
use core::$T_i::*;
|
||||||
|
@ -205,4 +203,4 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
));
|
)}
|
||||||
|
|
|
@ -14,13 +14,20 @@ use core::num::{NumCast, cast};
|
||||||
use core::ops::{Add, Sub, Mul, Div, Rem};
|
use core::ops::{Add, Sub, Mul, Div, Rem};
|
||||||
use core::kinds::Copy;
|
use core::kinds::Copy;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
mod int_macros;
|
mod int_macros;
|
||||||
|
|
||||||
mod i8;
|
mod i8;
|
||||||
mod i16;
|
mod i16;
|
||||||
mod i32;
|
mod i32;
|
||||||
mod i64;
|
mod i64;
|
||||||
mod int;
|
mod int;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
mod uint_macros;
|
mod uint_macros;
|
||||||
|
|
||||||
mod u8;
|
mod u8;
|
||||||
mod u16;
|
mod u16;
|
||||||
mod u32;
|
mod u32;
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
macro_rules! uint_module { ($T:ty, $T_i:ident) => (
|
||||||
|
|
||||||
macro_rules! uint_module (($T:ty, $T_i:ident) => (
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::$T_i::*;
|
use core::$T_i::*;
|
||||||
|
@ -125,4 +123,5 @@ mod tests {
|
||||||
assert!(5u.checked_div(0) == None);
|
assert!(5u.checked_div(0) == None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
));
|
|
||||||
|
)}
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
#![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_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
||||||
#![feature(phase, unboxed_closures, associated_types)]
|
#![feature(unboxed_closures, associated_types)]
|
||||||
|
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
#[cfg(test)] #[macro_use] extern crate log;
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||||
html_playground_url = "http://play.rust-lang.org/")]
|
html_playground_url = "http://play.rust-lang.org/")]
|
||||||
|
|
||||||
#![feature(macro_rules, globs, slicing_syntax)]
|
#![feature(globs, slicing_syntax)]
|
||||||
#![feature(associated_types)]
|
#![feature(associated_types)]
|
||||||
|
|
||||||
pub use self::Piece::*;
|
pub use self::Piece::*;
|
||||||
|
|
|
@ -85,11 +85,11 @@
|
||||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||||
html_playground_url = "http://play.rust-lang.org/")]
|
html_playground_url = "http://play.rust-lang.org/")]
|
||||||
#![feature(globs, phase, slicing_syntax)]
|
#![feature(globs, slicing_syntax)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
#[cfg(test)] #[macro_use] extern crate log;
|
||||||
|
|
||||||
use self::Name::*;
|
use self::Name::*;
|
||||||
use self::HasArg::*;
|
use self::HasArg::*;
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! #![feature(phase)]
|
//! #[macro_use] extern crate log;
|
||||||
//! #[phase(plugin, link)] extern crate log;
|
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! debug!("this is a debug {}", "message");
|
//! debug!("this is a debug {}", "message");
|
||||||
|
@ -183,7 +182,10 @@ use regex::Regex;
|
||||||
|
|
||||||
use directive::LOG_LEVEL_NAMES;
|
use directive::LOG_LEVEL_NAMES;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
mod directive;
|
mod directive;
|
||||||
|
|
||||||
/// Maximum logging level of a module that can be specified. Common logging
|
/// Maximum logging level of a module that can be specified. Common logging
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
//! Logging macros
|
//! Logging macros
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
/// The standard logging macro
|
/// The standard logging macro
|
||||||
///
|
///
|
||||||
/// This macro will generically log over a provided level (of type u32) with a
|
/// This macro will generically log over a provided level (of type u32) with a
|
||||||
|
@ -21,8 +19,7 @@
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(phase)]
|
/// #[macro_use] extern crate log;
|
||||||
/// #[phase(plugin, link)] extern crate log;
|
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// log!(log::WARN, "this is a warning {}", "message");
|
/// log!(log::WARN, "this is a warning {}", "message");
|
||||||
|
@ -70,8 +67,7 @@ macro_rules! log {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(phase)]
|
/// #[macro_use] extern crate log;
|
||||||
/// #[phase(plugin, link)] extern crate log;
|
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let error = 3u;
|
/// let error = 3u;
|
||||||
|
@ -96,8 +92,7 @@ macro_rules! error {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(phase)]
|
/// #[macro_use] extern crate log;
|
||||||
/// #[phase(plugin, link)] extern crate log;
|
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let code = 3u;
|
/// let code = 3u;
|
||||||
|
@ -121,8 +116,7 @@ macro_rules! warn {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(phase)]
|
/// #[macro_use] extern crate log;
|
||||||
/// #[phase(plugin, link)] extern crate log;
|
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let ret = 3;
|
/// let ret = 3;
|
||||||
|
@ -148,8 +142,7 @@ macro_rules! info {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(phase)]
|
/// #[macro_use] extern crate log;
|
||||||
/// #[phase(plugin, link)] extern crate log;
|
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// debug!("x = {x}, y = {y}", x=10, y=20);
|
/// debug!("x = {x}, y = {y}", x=10, y=20);
|
||||||
|
@ -172,8 +165,7 @@ macro_rules! debug {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(phase)]
|
/// #[macro_use] extern crate log;
|
||||||
/// #[phase(plugin, link)] extern crate log;
|
|
||||||
///
|
///
|
||||||
/// struct Point { x: int, y: int }
|
/// struct Point { x: int, y: int }
|
||||||
/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
|
/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
|
||||||
|
|
|
@ -297,7 +297,7 @@ mod tests {
|
||||||
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
|
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
|
||||||
// 1, internally; modulo a modulo operation).
|
// 1, internally; modulo a modulo operation).
|
||||||
|
|
||||||
macro_rules! t (
|
macro_rules! t {
|
||||||
($items:expr, $expected:expr) => {{
|
($items:expr, $expected:expr) => {{
|
||||||
let mut items = $items;
|
let mut items = $items;
|
||||||
let wc = WeightedChoice::new(items.as_mut_slice());
|
let wc = WeightedChoice::new(items.as_mut_slice());
|
||||||
|
@ -309,7 +309,7 @@ mod tests {
|
||||||
assert_eq!(wc.ind_sample(&mut rng), val)
|
assert_eq!(wc.ind_sample(&mut rng), val)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(vec!(Weighted { weight: 1, item: 10i}), [10]);
|
t!(vec!(Weighted { weight: 1, item: 10i}), [10]);
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_integers() {
|
fn test_integers() {
|
||||||
let mut rng = ::test::rng();
|
let mut rng = ::test::rng();
|
||||||
macro_rules! t (
|
macro_rules! t {
|
||||||
($($ty:ty),*) => {{
|
($($ty:ty),*) => {{
|
||||||
$(
|
$(
|
||||||
let v: &[($ty, $ty)] = &[(0, 10),
|
let v: &[($ty, $ty)] = &[(0, 10),
|
||||||
|
@ -199,7 +199,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
t!(i8, i16, i32, i64, int,
|
t!(i8, i16, i32, i64, int,
|
||||||
u8, u16, u32, u64, uint)
|
u8, u16, u32, u64, uint)
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_floats() {
|
fn test_floats() {
|
||||||
let mut rng = ::test::rng();
|
let mut rng = ::test::rng();
|
||||||
macro_rules! t (
|
macro_rules! t {
|
||||||
($($ty:ty),*) => {{
|
($($ty:ty),*) => {{
|
||||||
$(
|
$(
|
||||||
let v: &[($ty, $ty)] = &[(0.0, 100.0),
|
let v: &[($ty, $ty)] = &[(0.0, 100.0),
|
||||||
|
@ -225,7 +225,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(f32, f64)
|
t!(f32, f64)
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl IsaacRng {
|
||||||
let mut g = a;
|
let mut g = a;
|
||||||
let mut h = a;
|
let mut h = a;
|
||||||
|
|
||||||
macro_rules! mix(
|
macro_rules! mix {
|
||||||
() => {{
|
() => {{
|
||||||
a^=b<<11; d+=a; b+=c;
|
a^=b<<11; d+=a; b+=c;
|
||||||
b^=c>>2; e+=b; c+=d;
|
b^=c>>2; e+=b; c+=d;
|
||||||
|
@ -80,14 +80,14 @@ impl IsaacRng {
|
||||||
g^=h<<8; b+=g; h+=a;
|
g^=h<<8; b+=g; h+=a;
|
||||||
h^=a>>9; c+=h; a+=b;
|
h^=a>>9; c+=h; a+=b;
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
for _ in range(0u, 4) {
|
for _ in range(0u, 4) {
|
||||||
mix!();
|
mix!();
|
||||||
}
|
}
|
||||||
|
|
||||||
if use_rsl {
|
if use_rsl {
|
||||||
macro_rules! memloop (
|
macro_rules! memloop {
|
||||||
($arr:expr) => {{
|
($arr:expr) => {{
|
||||||
for i in range_step(0, RAND_SIZE as uint, 8) {
|
for i in range_step(0, RAND_SIZE as uint, 8) {
|
||||||
a+=$arr[i ]; b+=$arr[i+1];
|
a+=$arr[i ]; b+=$arr[i+1];
|
||||||
|
@ -101,7 +101,7 @@ impl IsaacRng {
|
||||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
memloop!(self.rsl);
|
memloop!(self.rsl);
|
||||||
memloop!(self.mem);
|
memloop!(self.mem);
|
||||||
|
@ -129,14 +129,14 @@ impl IsaacRng {
|
||||||
|
|
||||||
static MIDPOINT: uint = (RAND_SIZE / 2) as uint;
|
static MIDPOINT: uint = (RAND_SIZE / 2) as uint;
|
||||||
|
|
||||||
macro_rules! ind (($x:expr) => {
|
macro_rules! ind {
|
||||||
self.mem[(($x >> 2) as uint & ((RAND_SIZE - 1) as uint))]
|
($x:expr) => ( self.mem[(($x >> 2) as uint & ((RAND_SIZE - 1) as uint))] )
|
||||||
});
|
}
|
||||||
|
|
||||||
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
|
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
|
||||||
for &(mr_offset, m2_offset) in r.iter() {
|
for &(mr_offset, m2_offset) in r.iter() {
|
||||||
|
|
||||||
macro_rules! rngstepp(
|
macro_rules! rngstepp {
|
||||||
($j:expr, $shift:expr) => {{
|
($j:expr, $shift:expr) => {{
|
||||||
let base = $j;
|
let base = $j;
|
||||||
let mix = a << $shift as uint;
|
let mix = a << $shift as uint;
|
||||||
|
@ -149,8 +149,9 @@ impl IsaacRng {
|
||||||
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
||||||
self.rsl[base + mr_offset] = b;
|
self.rsl[base + mr_offset] = b;
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
macro_rules! rngstepn(
|
|
||||||
|
macro_rules! rngstepn {
|
||||||
($j:expr, $shift:expr) => {{
|
($j:expr, $shift:expr) => {{
|
||||||
let base = $j;
|
let base = $j;
|
||||||
let mix = a >> $shift as uint;
|
let mix = a >> $shift as uint;
|
||||||
|
@ -163,7 +164,7 @@ impl IsaacRng {
|
||||||
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
||||||
self.rsl[base + mr_offset] = b;
|
self.rsl[base + mr_offset] = b;
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
for i in range_step(0u, MIDPOINT, 4) {
|
for i in range_step(0u, MIDPOINT, 4) {
|
||||||
rngstepp!(i + 0, 13);
|
rngstepp!(i + 0, 13);
|
||||||
|
@ -301,15 +302,15 @@ impl Isaac64Rng {
|
||||||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||||
/// randomly).
|
/// randomly).
|
||||||
fn init(&mut self, use_rsl: bool) {
|
fn init(&mut self, use_rsl: bool) {
|
||||||
macro_rules! init (
|
macro_rules! init {
|
||||||
($var:ident) => (
|
($var:ident) => (
|
||||||
let mut $var = 0x9e3779b97f4a7c13;
|
let mut $var = 0x9e3779b97f4a7c13;
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
init!(a); init!(b); init!(c); init!(d);
|
init!(a); init!(b); init!(c); init!(d);
|
||||||
init!(e); init!(f); init!(g); init!(h);
|
init!(e); init!(f); init!(g); init!(h);
|
||||||
|
|
||||||
macro_rules! mix(
|
macro_rules! mix {
|
||||||
() => {{
|
() => {{
|
||||||
a-=e; f^=h>>9; h+=a;
|
a-=e; f^=h>>9; h+=a;
|
||||||
b-=f; g^=a<<9; a+=b;
|
b-=f; g^=a<<9; a+=b;
|
||||||
|
@ -320,14 +321,14 @@ impl Isaac64Rng {
|
||||||
g-=c; d^=f>>17; f+=g;
|
g-=c; d^=f>>17; f+=g;
|
||||||
h-=d; e^=g<<14; g+=h;
|
h-=d; e^=g<<14; g+=h;
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
for _ in range(0u, 4) {
|
for _ in range(0u, 4) {
|
||||||
mix!();
|
mix!();
|
||||||
}
|
}
|
||||||
|
|
||||||
if use_rsl {
|
if use_rsl {
|
||||||
macro_rules! memloop (
|
macro_rules! memloop {
|
||||||
($arr:expr) => {{
|
($arr:expr) => {{
|
||||||
for i in range(0, RAND_SIZE_64 / 8).map(|i| i * 8) {
|
for i in range(0, RAND_SIZE_64 / 8).map(|i| i * 8) {
|
||||||
a+=$arr[i ]; b+=$arr[i+1];
|
a+=$arr[i ]; b+=$arr[i+1];
|
||||||
|
@ -341,7 +342,7 @@ impl Isaac64Rng {
|
||||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
memloop!(self.rsl);
|
memloop!(self.rsl);
|
||||||
memloop!(self.mem);
|
memloop!(self.mem);
|
||||||
|
@ -366,16 +367,16 @@ impl Isaac64Rng {
|
||||||
let mut b = self.b + self.c;
|
let mut b = self.b + self.c;
|
||||||
const MIDPOINT: uint = RAND_SIZE_64 / 2;
|
const MIDPOINT: uint = RAND_SIZE_64 / 2;
|
||||||
const MP_VEC: [(uint, uint); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
|
const MP_VEC: [(uint, uint); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
|
||||||
macro_rules! ind (
|
macro_rules! ind {
|
||||||
($x:expr) => {
|
($x:expr) => {
|
||||||
*self.mem.get_unchecked(($x as uint >> 3) & (RAND_SIZE_64 - 1))
|
*self.mem.get_unchecked(($x as uint >> 3) & (RAND_SIZE_64 - 1))
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
for &(mr_offset, m2_offset) in MP_VEC.iter() {
|
for &(mr_offset, m2_offset) in MP_VEC.iter() {
|
||||||
for base in range(0, MIDPOINT / 4).map(|i| i * 4) {
|
for base in range(0, MIDPOINT / 4).map(|i| i * 4) {
|
||||||
|
|
||||||
macro_rules! rngstepp(
|
macro_rules! rngstepp {
|
||||||
($j:expr, $shift:expr) => {{
|
($j:expr, $shift:expr) => {{
|
||||||
let base = base + $j;
|
let base = base + $j;
|
||||||
let mix = a ^ (a << $shift as uint);
|
let mix = a ^ (a << $shift as uint);
|
||||||
|
@ -391,8 +392,9 @@ impl Isaac64Rng {
|
||||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
macro_rules! rngstepn(
|
|
||||||
|
macro_rules! rngstepn {
|
||||||
($j:expr, $shift:expr) => {{
|
($j:expr, $shift:expr) => {{
|
||||||
let base = base + $j;
|
let base = base + $j;
|
||||||
let mix = a ^ (a >> $shift as uint);
|
let mix = a ^ (a >> $shift as uint);
|
||||||
|
@ -408,7 +410,8 @@ impl Isaac64Rng {
|
||||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
);
|
}
|
||||||
|
|
||||||
rngstepp!(0u, 21);
|
rngstepp!(0u, 21);
|
||||||
rngstepn!(1u, 5);
|
rngstepn!(1u, 5);
|
||||||
rngstepp!(2u, 12);
|
rngstepp!(2u, 12);
|
||||||
|
|
|
@ -29,11 +29,29 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![experimental]
|
#![experimental]
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)]
|
#[phase(plugin, link)]
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate std;
|
#[cfg(not(stage0))]
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
#[macro_use]
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
#[cfg(all(test, stage0))]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[cfg(all(test, stage0))]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,14 @@
|
||||||
|
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
|
|
||||||
#[phase(plugin, link)] extern crate log;
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
#[cfg(test)] extern crate test;
|
#[cfg(test)] extern crate test;
|
||||||
|
|
||||||
pub use self::EbmlEncoderTag::*;
|
pub use self::EbmlEncoderTag::*;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
html_playground_url = "http://play.rust-lang.org/")]
|
html_playground_url = "http://play.rust-lang.org/")]
|
||||||
|
|
||||||
#![allow(unknown_features)]
|
#![allow(unknown_features)]
|
||||||
#![feature(macro_rules, phase, slicing_syntax, globs)]
|
#![feature(macro_rules, slicing_syntax, globs)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(associated_types)]
|
#![feature(associated_types)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
|
@ -40,8 +40,22 @@ extern crate rustc_back;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate rbml;
|
extern crate rbml;
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
#[phase(plugin, link)] extern crate syntax;
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
extern crate "serialize" as rustc_serialize; // used by deriving
|
extern crate "serialize" as rustc_serialize; // used by deriving
|
||||||
|
|
||||||
|
|
|
@ -167,21 +167,27 @@ impl LintStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_builtin(&mut self, sess: Option<&Session>) {
|
pub fn register_builtin(&mut self, sess: Option<&Session>) {
|
||||||
macro_rules! add_builtin ( ( $sess:ident, $($name:ident),*, ) => (
|
macro_rules! add_builtin {
|
||||||
|
($sess:ident, $($name:ident),*,) => (
|
||||||
{$(
|
{$(
|
||||||
self.register_pass($sess, false, box builtin::$name as LintPassObject);
|
self.register_pass($sess, false, box builtin::$name as LintPassObject);
|
||||||
)*}
|
)*}
|
||||||
));
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! add_builtin_with_new ( ( $sess:ident, $($name:ident),*, ) => (
|
macro_rules! add_builtin_with_new {
|
||||||
|
($sess:ident, $($name:ident),*,) => (
|
||||||
{$(
|
{$(
|
||||||
self.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
|
self.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
|
||||||
)*}
|
)*}
|
||||||
));
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => (
|
macro_rules! add_lint_group {
|
||||||
|
($sess:ident, $name:expr, $($lint:ident),*) => (
|
||||||
self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
|
self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
|
||||||
));
|
)
|
||||||
|
}
|
||||||
|
|
||||||
add_builtin!(sess,
|
add_builtin!(sess,
|
||||||
HardwiredLints,
|
HardwiredLints,
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
||||||
//! in `context.rs`.
|
//! in `context.rs`.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
pub use self::Level::*;
|
pub use self::Level::*;
|
||||||
pub use self::LintSource::*;
|
pub use self::LintSource::*;
|
||||||
|
|
||||||
|
|
|
@ -206,8 +206,8 @@ pub const tag_native_libraries_name: uint = 0x89;
|
||||||
pub const tag_native_libraries_kind: uint = 0x8a;
|
pub const tag_native_libraries_kind: uint = 0x8a;
|
||||||
|
|
||||||
pub const tag_plugin_registrar_fn: uint = 0x8b;
|
pub const tag_plugin_registrar_fn: uint = 0x8b;
|
||||||
pub const tag_exported_macros: uint = 0x8c;
|
|
||||||
pub const tag_macro_def: uint = 0x8d;
|
// GAP 0x8c, 0x8d
|
||||||
|
|
||||||
pub const tag_method_argument_names: uint = 0x8e;
|
pub const tag_method_argument_names: uint = 0x8e;
|
||||||
pub const tag_method_argument_name: uint = 0x8f;
|
pub const tag_method_argument_name: uint = 0x8f;
|
||||||
|
@ -261,3 +261,7 @@ pub const tag_associated_type_names: uint = 0xb2;
|
||||||
pub const tag_associated_type_name: uint = 0xb3;
|
pub const tag_associated_type_name: uint = 0xb3;
|
||||||
|
|
||||||
pub const tag_polarity: uint = 0xb4;
|
pub const tag_polarity: uint = 0xb4;
|
||||||
|
|
||||||
|
pub const tag_macro_defs: uint = 0xb5;
|
||||||
|
pub const tag_macro_def: uint = 0xb6;
|
||||||
|
pub const tag_macro_def_body: uint = 0xb7;
|
||||||
|
|
|
@ -16,11 +16,10 @@ use back::svh::Svh;
|
||||||
use session::{config, Session};
|
use session::{config, Session};
|
||||||
use session::search_paths::PathKind;
|
use session::search_paths::PathKind;
|
||||||
use metadata::cstore;
|
use metadata::cstore;
|
||||||
use metadata::cstore::{CStore, CrateSource};
|
use metadata::cstore::{CStore, CrateSource, MetadataBlob};
|
||||||
use metadata::decoder;
|
use metadata::decoder;
|
||||||
use metadata::loader;
|
use metadata::loader;
|
||||||
use metadata::loader::CratePaths;
|
use metadata::loader::CratePaths;
|
||||||
use plugin::load::PluginMetadata;
|
|
||||||
use util::nodemap::FnvHashMap;
|
use util::nodemap::FnvHashMap;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -29,43 +28,27 @@ use syntax::ast;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::codemap::{Span};
|
use syntax::codemap::{Span, mk_sp};
|
||||||
use syntax::diagnostic::SpanHandler;
|
use syntax::diagnostic::SpanHandler;
|
||||||
|
use syntax::parse;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
use util::fs;
|
use util::fs;
|
||||||
|
use log;
|
||||||
|
|
||||||
struct Env<'a> {
|
pub struct CrateReader<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
next_crate_num: ast::CrateNum,
|
next_crate_num: ast::CrateNum,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverses an AST, reading all the information about use'd crates and extern
|
impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
|
||||||
// libraries necessary for later resolving, typechecking, linking, etc.
|
|
||||||
pub fn read_crates(sess: &Session,
|
|
||||||
krate: &ast::Crate) {
|
|
||||||
let mut e = Env {
|
|
||||||
sess: sess,
|
|
||||||
next_crate_num: sess.cstore.next_crate_num(),
|
|
||||||
};
|
|
||||||
visit_crate(&e, krate);
|
|
||||||
visit::walk_crate(&mut e, krate);
|
|
||||||
dump_crates(&sess.cstore);
|
|
||||||
warn_if_multiple_versions(sess.diagnostic(), &sess.cstore);
|
|
||||||
|
|
||||||
for &(ref name, kind) in sess.opts.libs.iter() {
|
|
||||||
register_native_lib(sess, None, name.clone(), kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'v> visit::Visitor<'v> for Env<'a> {
|
|
||||||
fn visit_view_item(&mut self, a: &ast::ViewItem) {
|
fn visit_view_item(&mut self, a: &ast::ViewItem) {
|
||||||
visit_view_item(self, a);
|
self.process_view_item(a);
|
||||||
visit::walk_view_item(self, a);
|
visit::walk_view_item(self, a);
|
||||||
}
|
}
|
||||||
fn visit_item(&mut self, a: &ast::Item) {
|
fn visit_item(&mut self, a: &ast::Item) {
|
||||||
visit_item(self, a);
|
self.process_item(a);
|
||||||
visit::walk_item(self, a);
|
visit::walk_item(self, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,42 +88,8 @@ fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_crate(e: &Env, c: &ast::Crate) {
|
|
||||||
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
|
|
||||||
match a.value_str() {
|
|
||||||
Some(ref linkarg) => e.sess.cstore.add_used_link_args(linkarg.get()),
|
|
||||||
None => { /* fallthrough */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_link(i: &ast::ViewItem) -> bool {
|
fn should_link(i: &ast::ViewItem) -> bool {
|
||||||
i.attrs.iter().all(|attr| {
|
!attr::contains_name(i.attrs[], "no_link")
|
||||||
attr.name().get() != "phase" ||
|
|
||||||
attr.meta_item_list().map_or(false, |phases| {
|
|
||||||
attr::contains_name(phases[], "link")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
|
|
||||||
if !should_link(i) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match extract_crate_info(e, i) {
|
|
||||||
Some(info) => {
|
|
||||||
let (cnum, _, _) = resolve_crate(e,
|
|
||||||
&None,
|
|
||||||
info.ident[],
|
|
||||||
info.name[],
|
|
||||||
None,
|
|
||||||
i.span,
|
|
||||||
PathKind::Crate);
|
|
||||||
e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
|
||||||
}
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CrateInfo {
|
struct CrateInfo {
|
||||||
|
@ -150,32 +99,6 @@ struct CrateInfo {
|
||||||
should_link: bool,
|
should_link: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option<CrateInfo> {
|
|
||||||
match i.node {
|
|
||||||
ast::ViewItemExternCrate(ident, ref path_opt, id) => {
|
|
||||||
let ident = token::get_ident(ident);
|
|
||||||
debug!("resolving extern crate stmt. ident: {} path_opt: {}",
|
|
||||||
ident, path_opt);
|
|
||||||
let name = match *path_opt {
|
|
||||||
Some((ref path_str, _)) => {
|
|
||||||
let name = path_str.get().to_string();
|
|
||||||
validate_crate_name(Some(e.sess), name[],
|
|
||||||
Some(i.span));
|
|
||||||
name
|
|
||||||
}
|
|
||||||
None => ident.get().to_string(),
|
|
||||||
};
|
|
||||||
Some(CrateInfo {
|
|
||||||
ident: ident.get().to_string(),
|
|
||||||
name: name,
|
|
||||||
id: id,
|
|
||||||
should_link: should_link(i),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
||||||
let err = |&: s: &str| {
|
let err = |&: s: &str| {
|
||||||
match (sp, sess) {
|
match (sp, sess) {
|
||||||
|
@ -198,85 +121,6 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(e: &Env, i: &ast::Item) {
|
|
||||||
match i.node {
|
|
||||||
ast::ItemForeignMod(ref fm) => {
|
|
||||||
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, add all of the custom link_args attributes
|
|
||||||
let link_args = i.attrs.iter()
|
|
||||||
.filter_map(|at| if at.name() == "link_args" {
|
|
||||||
Some(at)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.collect::<Vec<&ast::Attribute>>();
|
|
||||||
for m in link_args.iter() {
|
|
||||||
match m.value_str() {
|
|
||||||
Some(linkarg) => e.sess.cstore.add_used_link_args(linkarg.get()),
|
|
||||||
None => { /* fallthrough */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, process all of the #[link(..)]-style arguments
|
|
||||||
let link_args = i.attrs.iter()
|
|
||||||
.filter_map(|at| if at.name() == "link" {
|
|
||||||
Some(at)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.collect::<Vec<&ast::Attribute>>();
|
|
||||||
for m in link_args.iter() {
|
|
||||||
match m.meta_item_list() {
|
|
||||||
Some(items) => {
|
|
||||||
let kind = items.iter().find(|k| {
|
|
||||||
k.name() == "kind"
|
|
||||||
}).and_then(|a| a.value_str());
|
|
||||||
let kind = match kind {
|
|
||||||
Some(k) => {
|
|
||||||
if k == "static" {
|
|
||||||
cstore::NativeStatic
|
|
||||||
} else if e.sess.target.target.options.is_like_osx
|
|
||||||
&& k == "framework" {
|
|
||||||
cstore::NativeFramework
|
|
||||||
} else if k == "framework" {
|
|
||||||
cstore::NativeFramework
|
|
||||||
} else if k == "dylib" {
|
|
||||||
cstore::NativeUnknown
|
|
||||||
} else {
|
|
||||||
e.sess.span_err(m.span,
|
|
||||||
format!("unknown kind: `{}`",
|
|
||||||
k)[]);
|
|
||||||
cstore::NativeUnknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => cstore::NativeUnknown
|
|
||||||
};
|
|
||||||
let n = items.iter().find(|n| {
|
|
||||||
n.name() == "name"
|
|
||||||
}).and_then(|a| a.value_str());
|
|
||||||
let n = match n {
|
|
||||||
Some(n) => n,
|
|
||||||
None => {
|
|
||||||
e.sess.span_err(m.span,
|
|
||||||
"#[link(...)] specified without \
|
|
||||||
`name = \"foo\"`");
|
|
||||||
InternedString::new("foo")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
register_native_lib(e.sess, Some(m.span),
|
|
||||||
n.get().to_string(), kind);
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_native_lib(sess: &Session,
|
fn register_native_lib(sess: &Session,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -304,10 +148,190 @@ fn register_native_lib(sess: &Session,
|
||||||
sess.cstore.add_used_library(name, kind);
|
sess.cstore.add_used_library(name, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn existing_match(e: &Env, name: &str,
|
pub struct PluginMetadata<'a> {
|
||||||
|
sess: &'a Session,
|
||||||
|
metadata: PMDSource,
|
||||||
|
dylib: Option<Path>,
|
||||||
|
info: CrateInfo,
|
||||||
|
vi_span: Span,
|
||||||
|
target_only: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PMDSource {
|
||||||
|
Registered(Rc<cstore::crate_metadata>),
|
||||||
|
Owned(MetadataBlob),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PMDSource {
|
||||||
|
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
|
||||||
|
match *self {
|
||||||
|
PMDSource::Registered(ref cmd) => cmd.data(),
|
||||||
|
PMDSource::Owned(ref mdb) => mdb.as_slice(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CrateReader<'a> {
|
||||||
|
pub fn new(sess: &'a Session) -> CrateReader<'a> {
|
||||||
|
CrateReader {
|
||||||
|
sess: sess,
|
||||||
|
next_crate_num: sess.cstore.next_crate_num(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverses an AST, reading all the information about use'd crates and extern
|
||||||
|
// libraries necessary for later resolving, typechecking, linking, etc.
|
||||||
|
pub fn read_crates(&mut self, krate: &ast::Crate) {
|
||||||
|
self.process_crate(krate);
|
||||||
|
visit::walk_crate(self, krate);
|
||||||
|
|
||||||
|
if log_enabled!(log::DEBUG) {
|
||||||
|
dump_crates(&self.sess.cstore);
|
||||||
|
}
|
||||||
|
warn_if_multiple_versions(self.sess.diagnostic(), &self.sess.cstore);
|
||||||
|
|
||||||
|
for &(ref name, kind) in self.sess.opts.libs.iter() {
|
||||||
|
register_native_lib(self.sess, None, name.clone(), kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_crate(&self, c: &ast::Crate) {
|
||||||
|
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
|
||||||
|
match a.value_str() {
|
||||||
|
Some(ref linkarg) => self.sess.cstore.add_used_link_args(linkarg.get()),
|
||||||
|
None => { /* fallthrough */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_view_item(&mut self, i: &ast::ViewItem) {
|
||||||
|
if !should_link(i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.extract_crate_info(i) {
|
||||||
|
Some(info) => {
|
||||||
|
let (cnum, _, _) = self.resolve_crate(&None,
|
||||||
|
info.ident[],
|
||||||
|
info.name[],
|
||||||
|
None,
|
||||||
|
i.span,
|
||||||
|
PathKind::Crate);
|
||||||
|
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
||||||
|
}
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_crate_info(&self, i: &ast::ViewItem) -> Option<CrateInfo> {
|
||||||
|
match i.node {
|
||||||
|
ast::ViewItemExternCrate(ident, ref path_opt, id) => {
|
||||||
|
let ident = token::get_ident(ident);
|
||||||
|
debug!("resolving extern crate stmt. ident: {} path_opt: {}",
|
||||||
|
ident, path_opt);
|
||||||
|
let name = match *path_opt {
|
||||||
|
Some((ref path_str, _)) => {
|
||||||
|
let name = path_str.get().to_string();
|
||||||
|
validate_crate_name(Some(self.sess), name[],
|
||||||
|
Some(i.span));
|
||||||
|
name
|
||||||
|
}
|
||||||
|
None => ident.get().to_string(),
|
||||||
|
};
|
||||||
|
Some(CrateInfo {
|
||||||
|
ident: ident.get().to_string(),
|
||||||
|
name: name,
|
||||||
|
id: id,
|
||||||
|
should_link: should_link(i),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_item(&self, i: &ast::Item) {
|
||||||
|
match i.node {
|
||||||
|
ast::ItemForeignMod(ref fm) => {
|
||||||
|
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, add all of the custom link_args attributes
|
||||||
|
let link_args = i.attrs.iter()
|
||||||
|
.filter_map(|at| if at.name() == "link_args" {
|
||||||
|
Some(at)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<&ast::Attribute>>();
|
||||||
|
for m in link_args.iter() {
|
||||||
|
match m.value_str() {
|
||||||
|
Some(linkarg) => self.sess.cstore.add_used_link_args(linkarg.get()),
|
||||||
|
None => { /* fallthrough */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, process all of the #[link(..)]-style arguments
|
||||||
|
let link_args = i.attrs.iter()
|
||||||
|
.filter_map(|at| if at.name() == "link" {
|
||||||
|
Some(at)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<&ast::Attribute>>();
|
||||||
|
for m in link_args.iter() {
|
||||||
|
match m.meta_item_list() {
|
||||||
|
Some(items) => {
|
||||||
|
let kind = items.iter().find(|k| {
|
||||||
|
k.name() == "kind"
|
||||||
|
}).and_then(|a| a.value_str());
|
||||||
|
let kind = match kind {
|
||||||
|
Some(k) => {
|
||||||
|
if k == "static" {
|
||||||
|
cstore::NativeStatic
|
||||||
|
} else if self.sess.target.target.options.is_like_osx
|
||||||
|
&& k == "framework" {
|
||||||
|
cstore::NativeFramework
|
||||||
|
} else if k == "framework" {
|
||||||
|
cstore::NativeFramework
|
||||||
|
} else if k == "dylib" {
|
||||||
|
cstore::NativeUnknown
|
||||||
|
} else {
|
||||||
|
self.sess.span_err(m.span,
|
||||||
|
format!("unknown kind: `{}`",
|
||||||
|
k)[]);
|
||||||
|
cstore::NativeUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => cstore::NativeUnknown
|
||||||
|
};
|
||||||
|
let n = items.iter().find(|n| {
|
||||||
|
n.name() == "name"
|
||||||
|
}).and_then(|a| a.value_str());
|
||||||
|
let n = match n {
|
||||||
|
Some(n) => n,
|
||||||
|
None => {
|
||||||
|
self.sess.span_err(m.span,
|
||||||
|
"#[link(...)] specified without \
|
||||||
|
`name = \"foo\"`");
|
||||||
|
InternedString::new("foo")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
register_native_lib(self.sess, Some(m.span),
|
||||||
|
n.get().to_string(), kind);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn existing_match(&self, name: &str,
|
||||||
hash: Option<&Svh>) -> Option<ast::CrateNum> {
|
hash: Option<&Svh>) -> Option<ast::CrateNum> {
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
e.sess.cstore.iter_crate_data(|cnum, data| {
|
self.sess.cstore.iter_crate_data(|cnum, data| {
|
||||||
if data.name != name { return }
|
if data.name != name { return }
|
||||||
|
|
||||||
match hash {
|
match hash {
|
||||||
|
@ -325,8 +349,8 @@ fn existing_match(e: &Env, name: &str,
|
||||||
// We're also sure to compare *paths*, not actual byte slices. The
|
// We're also sure to compare *paths*, not actual byte slices. The
|
||||||
// `source` stores paths which are normalized which may be different
|
// `source` stores paths which are normalized which may be different
|
||||||
// from the strings on the command line.
|
// from the strings on the command line.
|
||||||
let source = e.sess.cstore.get_used_crate_source(cnum).unwrap();
|
let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
|
||||||
match e.sess.opts.externs.get(name) {
|
match self.sess.opts.externs.get(name) {
|
||||||
Some(locs) => {
|
Some(locs) => {
|
||||||
let found = locs.iter().any(|l| {
|
let found = locs.iter().any(|l| {
|
||||||
let l = fs::realpath(&Path::new(l[])).ok();
|
let l = fs::realpath(&Path::new(l[])).ok();
|
||||||
|
@ -340,9 +364,9 @@ fn existing_match(e: &Env, name: &str,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_crate<'a>(e: &mut Env,
|
fn register_crate(&mut self,
|
||||||
root: &Option<CratePaths>,
|
root: &Option<CratePaths>,
|
||||||
ident: &str,
|
ident: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -351,8 +375,8 @@ fn register_crate<'a>(e: &mut Env,
|
||||||
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
||||||
cstore::CrateSource) {
|
cstore::CrateSource) {
|
||||||
// Claim this crate number and cache it
|
// Claim this crate number and cache it
|
||||||
let cnum = e.next_crate_num;
|
let cnum = self.next_crate_num;
|
||||||
e.next_crate_num += 1;
|
self.next_crate_num += 1;
|
||||||
|
|
||||||
// Stash paths for top-most crate locally if necessary.
|
// Stash paths for top-most crate locally if necessary.
|
||||||
let crate_paths = if root.is_none() {
|
let crate_paths = if root.is_none() {
|
||||||
|
@ -367,7 +391,7 @@ fn register_crate<'a>(e: &mut Env,
|
||||||
// Maintain a reference to the top most crate.
|
// Maintain a reference to the top most crate.
|
||||||
let root = if root.is_some() { root } else { &crate_paths };
|
let root = if root.is_some() { root } else { &crate_paths };
|
||||||
|
|
||||||
let cnum_map = resolve_crate_deps(e, root, lib.metadata.as_slice(), span);
|
let cnum_map = self.resolve_crate_deps(root, lib.metadata.as_slice(), span);
|
||||||
|
|
||||||
let loader::Library{ dylib, rlib, metadata } = lib;
|
let loader::Library{ dylib, rlib, metadata } = lib;
|
||||||
|
|
||||||
|
@ -385,12 +409,12 @@ fn register_crate<'a>(e: &mut Env,
|
||||||
cnum: cnum,
|
cnum: cnum,
|
||||||
};
|
};
|
||||||
|
|
||||||
e.sess.cstore.set_crate_data(cnum, cmeta.clone());
|
self.sess.cstore.set_crate_data(cnum, cmeta.clone());
|
||||||
e.sess.cstore.add_used_crate_source(source.clone());
|
self.sess.cstore.add_used_crate_source(source.clone());
|
||||||
(cnum, cmeta, source)
|
(cnum, cmeta, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_crate(e: &mut Env,
|
fn resolve_crate(&mut self,
|
||||||
root: &Option<CratePaths>,
|
root: &Option<CratePaths>,
|
||||||
ident: &str,
|
ident: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -399,32 +423,32 @@ fn resolve_crate(e: &mut Env,
|
||||||
kind: PathKind)
|
kind: PathKind)
|
||||||
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
||||||
cstore::CrateSource) {
|
cstore::CrateSource) {
|
||||||
match existing_match(e, name, hash) {
|
match self.existing_match(name, hash) {
|
||||||
None => {
|
None => {
|
||||||
let mut load_ctxt = loader::Context {
|
let mut load_ctxt = loader::Context {
|
||||||
sess: e.sess,
|
sess: self.sess,
|
||||||
span: span,
|
span: span,
|
||||||
ident: ident,
|
ident: ident,
|
||||||
crate_name: name,
|
crate_name: name,
|
||||||
hash: hash.map(|a| &*a),
|
hash: hash.map(|a| &*a),
|
||||||
filesearch: e.sess.target_filesearch(kind),
|
filesearch: self.sess.target_filesearch(kind),
|
||||||
triple: e.sess.opts.target_triple[],
|
triple: self.sess.opts.target_triple[],
|
||||||
root: root,
|
root: root,
|
||||||
rejected_via_hash: vec!(),
|
rejected_via_hash: vec!(),
|
||||||
rejected_via_triple: vec!(),
|
rejected_via_triple: vec!(),
|
||||||
should_match_name: true,
|
should_match_name: true,
|
||||||
};
|
};
|
||||||
let library = load_ctxt.load_library_crate();
|
let library = load_ctxt.load_library_crate();
|
||||||
register_crate(e, root, ident, name, span, library)
|
self.register_crate(root, ident, name, span, library)
|
||||||
}
|
}
|
||||||
Some(cnum) => (cnum,
|
Some(cnum) => (cnum,
|
||||||
e.sess.cstore.get_crate_data(cnum),
|
self.sess.cstore.get_crate_data(cnum),
|
||||||
e.sess.cstore.get_used_crate_source(cnum).unwrap())
|
self.sess.cstore.get_used_crate_source(cnum).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Go through the crate metadata and load any crates that it references
|
// Go through the crate metadata and load any crates that it references
|
||||||
fn resolve_crate_deps(e: &mut Env,
|
fn resolve_crate_deps(&mut self,
|
||||||
root: &Option<CratePaths>,
|
root: &Option<CratePaths>,
|
||||||
cdata: &[u8], span : Span)
|
cdata: &[u8], span : Span)
|
||||||
-> cstore::cnum_map {
|
-> cstore::cnum_map {
|
||||||
|
@ -433,7 +457,7 @@ fn resolve_crate_deps(e: &mut Env,
|
||||||
// numbers
|
// numbers
|
||||||
decoder::get_crate_deps(cdata).iter().map(|dep| {
|
decoder::get_crate_deps(cdata).iter().map(|dep| {
|
||||||
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
||||||
let (local_cnum, _, _) = resolve_crate(e, root,
|
let (local_cnum, _, _) = self.resolve_crate(root,
|
||||||
dep.name[],
|
dep.name[],
|
||||||
dep.name[],
|
dep.name[],
|
||||||
Some(&dep.hash),
|
Some(&dep.hash),
|
||||||
|
@ -441,35 +465,24 @@ fn resolve_crate_deps(e: &mut Env,
|
||||||
PathKind::Dependency);
|
PathKind::Dependency);
|
||||||
(dep.cnum, local_cnum)
|
(dep.cnum, local_cnum)
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PluginMetadataReader<'a> {
|
|
||||||
env: Env<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PluginMetadataReader<'a> {
|
|
||||||
pub fn new(sess: &'a Session) -> PluginMetadataReader<'a> {
|
|
||||||
PluginMetadataReader {
|
|
||||||
env: Env {
|
|
||||||
sess: sess,
|
|
||||||
next_crate_num: sess.cstore.next_crate_num(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_plugin_metadata(&mut self,
|
pub fn read_plugin_metadata<'b>(&'b mut self,
|
||||||
krate: &ast::ViewItem) -> PluginMetadata {
|
vi: &'b ast::ViewItem) -> PluginMetadata<'b> {
|
||||||
let info = extract_crate_info(&self.env, krate).unwrap();
|
let info = self.extract_crate_info(vi).unwrap();
|
||||||
let target_triple = self.env.sess.opts.target_triple[];
|
let target_triple = self.sess.opts.target_triple[];
|
||||||
let is_cross = target_triple != config::host_triple();
|
let is_cross = target_triple != config::host_triple();
|
||||||
let mut should_link = info.should_link && !is_cross;
|
let mut should_link = info.should_link && !is_cross;
|
||||||
|
let mut target_only = false;
|
||||||
|
let ident = info.ident.clone();
|
||||||
|
let name = info.name.clone();
|
||||||
let mut load_ctxt = loader::Context {
|
let mut load_ctxt = loader::Context {
|
||||||
sess: self.env.sess,
|
sess: self.sess,
|
||||||
span: krate.span,
|
span: vi.span,
|
||||||
ident: info.ident[],
|
ident: ident[],
|
||||||
crate_name: info.name[],
|
crate_name: name[],
|
||||||
hash: None,
|
hash: None,
|
||||||
filesearch: self.env.sess.host_filesearch(PathKind::Crate),
|
filesearch: self.sess.host_filesearch(PathKind::Crate),
|
||||||
triple: config::host_triple(),
|
triple: config::host_triple(),
|
||||||
root: &None,
|
root: &None,
|
||||||
rejected_via_hash: vec!(),
|
rejected_via_hash: vec!(),
|
||||||
|
@ -479,49 +492,106 @@ impl<'a> PluginMetadataReader<'a> {
|
||||||
let library = match load_ctxt.maybe_load_library_crate() {
|
let library = match load_ctxt.maybe_load_library_crate() {
|
||||||
Some(l) => l,
|
Some(l) => l,
|
||||||
None if is_cross => {
|
None if is_cross => {
|
||||||
// try loading from target crates (only valid if there are
|
// Try loading from target crates. This will abort later if we try to
|
||||||
// no syntax extensions)
|
// load a plugin registrar function,
|
||||||
load_ctxt.triple = target_triple;
|
target_only = true;
|
||||||
load_ctxt.filesearch = self.env.sess.target_filesearch(PathKind::Crate);
|
|
||||||
let lib = load_ctxt.load_library_crate();
|
|
||||||
if decoder::get_plugin_registrar_fn(lib.metadata.as_slice()).is_some() {
|
|
||||||
let message = format!("crate `{}` contains a plugin_registrar fn but \
|
|
||||||
only a version for triple `{}` could be found (need {})",
|
|
||||||
info.ident, target_triple, config::host_triple());
|
|
||||||
self.env.sess.span_err(krate.span, message[]);
|
|
||||||
// need to abort now because the syntax expansion
|
|
||||||
// code will shortly attempt to load and execute
|
|
||||||
// code from the found library.
|
|
||||||
self.env.sess.abort_if_errors();
|
|
||||||
}
|
|
||||||
should_link = info.should_link;
|
should_link = info.should_link;
|
||||||
lib
|
|
||||||
|
load_ctxt.triple = target_triple;
|
||||||
|
load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
|
||||||
|
load_ctxt.load_library_crate()
|
||||||
}
|
}
|
||||||
None => { load_ctxt.report_load_errs(); unreachable!() },
|
None => { load_ctxt.report_load_errs(); unreachable!() },
|
||||||
};
|
};
|
||||||
let macros = decoder::get_exported_macros(library.metadata.as_slice());
|
|
||||||
let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
|
let dylib = library.dylib.clone();
|
||||||
decoder::get_symbol(library.metadata.as_slice(), id)
|
let register = should_link && self.existing_match(info.name[], None).is_none();
|
||||||
});
|
let metadata = if register {
|
||||||
if library.dylib.is_none() && registrar.is_some() {
|
// Register crate now to avoid double-reading metadata
|
||||||
let message = format!("plugin crate `{}` only found in rlib format, \
|
let (_, cmd, _) = self.register_crate(&None, info.ident[],
|
||||||
but must be available in dylib format",
|
info.name[], vi.span, library);
|
||||||
info.ident);
|
PMDSource::Registered(cmd)
|
||||||
self.env.sess.span_err(krate.span, message[]);
|
} else {
|
||||||
// No need to abort because the loading code will just ignore this
|
// Not registering the crate; just hold on to the metadata
|
||||||
// empty dylib.
|
PMDSource::Owned(library.metadata)
|
||||||
}
|
|
||||||
let pc = PluginMetadata {
|
|
||||||
lib: library.dylib.clone(),
|
|
||||||
macros: macros,
|
|
||||||
registrar_symbol: registrar,
|
|
||||||
};
|
};
|
||||||
if should_link && existing_match(&self.env, info.name[],
|
|
||||||
None).is_none() {
|
PluginMetadata {
|
||||||
// register crate now to avoid double-reading metadata
|
sess: self.sess,
|
||||||
register_crate(&mut self.env, &None, info.ident[],
|
metadata: metadata,
|
||||||
info.name[], krate.span, library);
|
dylib: dylib,
|
||||||
|
info: info,
|
||||||
|
vi_span: vi.span,
|
||||||
|
target_only: target_only,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PluginMetadata<'a> {
|
||||||
|
/// Read exported macros
|
||||||
|
pub fn exported_macros(&self) -> Vec<ast::MacroDef> {
|
||||||
|
let imported_from = Some(token::intern(self.info.ident[]).ident());
|
||||||
|
let source_name = format!("<{} macros>", self.info.ident[]);
|
||||||
|
let mut macros = vec![];
|
||||||
|
decoder::each_exported_macro(self.metadata.as_slice(),
|
||||||
|
&*self.sess.cstore.intr,
|
||||||
|
|name, attrs, body| {
|
||||||
|
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
||||||
|
// quote_depth > 0.
|
||||||
|
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
|
||||||
|
self.sess.opts.cfg.clone(),
|
||||||
|
source_name.clone(),
|
||||||
|
body);
|
||||||
|
let lo = p.span.lo;
|
||||||
|
let body = p.parse_all_token_trees();
|
||||||
|
let span = mk_sp(lo, p.last_span.hi);
|
||||||
|
p.abort_if_errors();
|
||||||
|
macros.push(ast::MacroDef {
|
||||||
|
ident: name.ident(),
|
||||||
|
attrs: attrs,
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
span: span,
|
||||||
|
imported_from: imported_from,
|
||||||
|
// overridden in plugin/load.rs
|
||||||
|
export: false,
|
||||||
|
use_locally: false,
|
||||||
|
|
||||||
|
body: body,
|
||||||
|
});
|
||||||
|
true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
macros
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look for a plugin registrar. Returns library path and symbol name.
|
||||||
|
pub fn plugin_registrar(&self) -> Option<(Path, String)> {
|
||||||
|
if self.target_only {
|
||||||
|
// Need to abort before syntax expansion.
|
||||||
|
let message = format!("plugin crate `{}` is not available for triple `{}` \
|
||||||
|
(only found {})",
|
||||||
|
self.info.ident,
|
||||||
|
config::host_triple(),
|
||||||
|
self.sess.opts.target_triple);
|
||||||
|
self.sess.span_err(self.vi_span, message[]);
|
||||||
|
self.sess.abort_if_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
let registrar = decoder::get_plugin_registrar_fn(self.metadata.as_slice())
|
||||||
|
.map(|id| decoder::get_symbol(self.metadata.as_slice(), id));
|
||||||
|
|
||||||
|
match (self.dylib.as_ref(), registrar) {
|
||||||
|
(Some(dylib), Some(reg)) => Some((dylib.clone(), reg)),
|
||||||
|
(None, Some(_)) => {
|
||||||
|
let message = format!("plugin crate `{}` only found in rlib format, \
|
||||||
|
but must be available in dylib format",
|
||||||
|
self.info.ident);
|
||||||
|
self.sess.span_err(self.vi_span, message[]);
|
||||||
|
// No need to abort because the loading code will just ignore this
|
||||||
|
// empty dylib.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
pc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1353,15 +1353,16 @@ pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
|
||||||
.map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap())
|
.map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_exported_macros(data: &[u8]) -> Vec<String> {
|
pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
|
||||||
let macros = reader::get_doc(rbml::Doc::new(data),
|
F: FnMut(ast::Name, Vec<ast::Attribute>, String) -> bool,
|
||||||
tag_exported_macros);
|
{
|
||||||
let mut result = Vec::new();
|
let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
|
||||||
reader::tagged_docs(macros, tag_macro_def, |macro_doc| {
|
reader::tagged_docs(macros, tag_macro_def, |macro_doc| {
|
||||||
result.push(macro_doc.as_str().to_string());
|
let name = item_name(intr, macro_doc);
|
||||||
true
|
let attrs = get_attributes(macro_doc);
|
||||||
|
let body = reader::get_doc(macro_doc, tag_macro_def_body);
|
||||||
|
f(name, attrs, body.as_str().to_string())
|
||||||
});
|
});
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dylib_dependency_formats(cdata: Cmd)
|
pub fn get_dylib_dependency_formats(cdata: Cmd)
|
||||||
|
|
|
@ -42,6 +42,7 @@ use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::diagnostic::SpanHandler;
|
use syntax::diagnostic::SpanHandler;
|
||||||
use syntax::parse::token::special_idents;
|
use syntax::parse::token::special_idents;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
use syntax::print::pprust;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
|
@ -1817,25 +1818,21 @@ fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a span, write the text of that span into the output stream
|
|
||||||
/// as an exported macro
|
|
||||||
fn encode_macro_def(ecx: &EncodeContext,
|
|
||||||
rbml_w: &mut Encoder,
|
|
||||||
span: &syntax::codemap::Span) {
|
|
||||||
let def = ecx.tcx.sess.codemap().span_to_snippet(*span)
|
|
||||||
.expect("Unable to find source for macro");
|
|
||||||
rbml_w.start_tag(tag_macro_def);
|
|
||||||
rbml_w.wr_str(def[]);
|
|
||||||
rbml_w.end_tag();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize the text of the exported macros
|
/// Serialize the text of the exported macros
|
||||||
fn encode_macro_defs(ecx: &EncodeContext,
|
fn encode_macro_defs(rbml_w: &mut Encoder,
|
||||||
krate: &ast::Crate,
|
krate: &ast::Crate) {
|
||||||
rbml_w: &mut Encoder) {
|
rbml_w.start_tag(tag_macro_defs);
|
||||||
rbml_w.start_tag(tag_exported_macros);
|
for def in krate.exported_macros.iter() {
|
||||||
for item in krate.exported_macros.iter() {
|
rbml_w.start_tag(tag_macro_def);
|
||||||
encode_macro_def(ecx, rbml_w, &item.span);
|
|
||||||
|
encode_name(rbml_w, def.ident.name);
|
||||||
|
encode_attributes(rbml_w, def.attrs[]);
|
||||||
|
|
||||||
|
rbml_w.start_tag(tag_macro_def_body);
|
||||||
|
rbml_w.wr_str(pprust::tts_to_string(def.body[])[]);
|
||||||
|
rbml_w.end_tag();
|
||||||
|
|
||||||
|
rbml_w.end_tag();
|
||||||
}
|
}
|
||||||
rbml_w.end_tag();
|
rbml_w.end_tag();
|
||||||
}
|
}
|
||||||
|
@ -2153,7 +2150,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
|
||||||
|
|
||||||
// Encode macro definitions
|
// Encode macro definitions
|
||||||
i = rbml_w.writer.tell().unwrap();
|
i = rbml_w.writer.tell().unwrap();
|
||||||
encode_macro_defs(&ecx, krate, &mut rbml_w);
|
encode_macro_defs(&mut rbml_w, krate);
|
||||||
stats.macro_defs_bytes = rbml_w.writer.tell().unwrap() - i;
|
stats.macro_defs_bytes = rbml_w.writer.tell().unwrap() - i;
|
||||||
|
|
||||||
// Encode the types of all unboxed closures in this crate.
|
// Encode the types of all unboxed closures in this crate.
|
||||||
|
|
|
@ -503,7 +503,7 @@ pub fn eval_const_expr_partial(tcx: &ty::ctxt, e: &Expr) -> Result<const_val, St
|
||||||
"target type not found for const cast")
|
"target type not found for const cast")
|
||||||
});
|
});
|
||||||
|
|
||||||
macro_rules! define_casts(
|
macro_rules! define_casts {
|
||||||
($val:ident, {
|
($val:ident, {
|
||||||
$($ty_pat:pat => (
|
$($ty_pat:pat => (
|
||||||
$intermediate_ty:ty,
|
$intermediate_ty:ty,
|
||||||
|
@ -524,7 +524,7 @@ pub fn eval_const_expr_partial(tcx: &ty::ctxt, e: &Expr) -> Result<const_val, St
|
||||||
},)*
|
},)*
|
||||||
_ => Err("can't cast this type".to_string())
|
_ => Err("can't cast this type".to_string())
|
||||||
})
|
})
|
||||||
);
|
}
|
||||||
|
|
||||||
eval_const_expr_partial(tcx, &**base)
|
eval_const_expr_partial(tcx, &**base)
|
||||||
.and_then(|val| define_casts!(val, {
|
.and_then(|val| define_casts!(val, {
|
||||||
|
|
|
@ -6171,8 +6171,8 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
|
||||||
return state.result();
|
return state.result();
|
||||||
|
|
||||||
fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) {
|
fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) {
|
||||||
macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } );
|
macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } }
|
||||||
macro_rules! hash( ($e:expr) => { $e.hash(state) } );
|
macro_rules! hash { ($e:expr) => { $e.hash(state) } }
|
||||||
|
|
||||||
let region = |&: state: &mut sip::SipState, r: Region| {
|
let region = |&: state: &mut sip::SipState, r: Region| {
|
||||||
match r {
|
match r {
|
||||||
|
|
|
@ -8,47 +8,46 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Used by `rustc` when loading a plugin.
|
//! Used by `rustc` when loading a plugin, or a crate with exported macros.
|
||||||
|
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use metadata::creader::PluginMetadataReader;
|
use metadata::creader::CrateReader;
|
||||||
use plugin::registry::Registry;
|
use plugin::registry::Registry;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::dynamic_lib::DynamicLibrary;
|
use std::dynamic_lib::DynamicLibrary;
|
||||||
|
use std::collections::HashSet;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
use syntax::codemap::Span;
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::ptr::P;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
use syntax::ext::expand::ExportedMacros;
|
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
|
|
||||||
/// Plugin-related crate metadata.
|
|
||||||
pub struct PluginMetadata {
|
|
||||||
/// Source code of macros exported by the crate.
|
|
||||||
pub macros: Vec<String>,
|
|
||||||
/// Path to the shared library file.
|
|
||||||
pub lib: Option<Path>,
|
|
||||||
/// Symbol name of the plugin registrar function.
|
|
||||||
pub registrar_symbol: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pointer to a registrar function.
|
/// Pointer to a registrar function.
|
||||||
pub type PluginRegistrarFun =
|
pub type PluginRegistrarFun =
|
||||||
fn(&mut Registry);
|
fn(&mut Registry);
|
||||||
|
|
||||||
|
pub struct PluginRegistrar {
|
||||||
|
pub fun: PluginRegistrarFun,
|
||||||
|
pub args: P<ast::MetaItem>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Information about loaded plugins.
|
/// Information about loaded plugins.
|
||||||
pub struct Plugins {
|
pub struct Plugins {
|
||||||
/// Source code of exported macros.
|
/// Imported macros.
|
||||||
pub macros: Vec<ExportedMacros>,
|
pub macros: Vec<ast::MacroDef>,
|
||||||
/// Registrars, as function pointers.
|
/// Registrars, as function pointers.
|
||||||
pub registrars: Vec<PluginRegistrarFun>,
|
pub registrars: Vec<PluginRegistrar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PluginLoader<'a> {
|
struct PluginLoader<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
reader: PluginMetadataReader<'a>,
|
span_whitelist: HashSet<Span>,
|
||||||
|
reader: CrateReader<'a>,
|
||||||
plugins: Plugins,
|
plugins: Plugins,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +55,8 @@ impl<'a> PluginLoader<'a> {
|
||||||
fn new(sess: &'a Session) -> PluginLoader<'a> {
|
fn new(sess: &'a Session) -> PluginLoader<'a> {
|
||||||
PluginLoader {
|
PluginLoader {
|
||||||
sess: sess,
|
sess: sess,
|
||||||
reader: PluginMetadataReader::new(sess),
|
reader: CrateReader::new(sess),
|
||||||
|
span_whitelist: HashSet::new(),
|
||||||
plugins: Plugins {
|
plugins: Plugins {
|
||||||
macros: vec!(),
|
macros: vec!(),
|
||||||
registrars: vec!(),
|
registrars: vec!(),
|
||||||
|
@ -69,6 +69,14 @@ impl<'a> PluginLoader<'a> {
|
||||||
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
|
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
|
||||||
addl_plugins: Option<Plugins>) -> Plugins {
|
addl_plugins: Option<Plugins>) -> Plugins {
|
||||||
let mut loader = PluginLoader::new(sess);
|
let mut loader = PluginLoader::new(sess);
|
||||||
|
|
||||||
|
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||||
|
// crate root, because `$crate` won't work properly. Identify these by
|
||||||
|
// spans, because the crate map isn't set up yet.
|
||||||
|
for vi in krate.module.view_items.iter() {
|
||||||
|
loader.span_whitelist.insert(vi.span);
|
||||||
|
}
|
||||||
|
|
||||||
visit::walk_crate(&mut loader, krate);
|
visit::walk_crate(&mut loader, krate);
|
||||||
|
|
||||||
let mut plugins = loader.plugins;
|
let mut plugins = loader.plugins;
|
||||||
|
@ -89,41 +97,112 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
|
||||||
// note that macros aren't expanded yet, and therefore macros can't add plugins.
|
// note that macros aren't expanded yet, and therefore macros can't add plugins.
|
||||||
impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
|
impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
|
||||||
fn visit_view_item(&mut self, vi: &ast::ViewItem) {
|
fn visit_view_item(&mut self, vi: &ast::ViewItem) {
|
||||||
|
// We're only interested in `extern crate`.
|
||||||
match vi.node {
|
match vi.node {
|
||||||
ast::ViewItemExternCrate(name, _, _) => {
|
ast::ViewItemExternCrate(..) => (),
|
||||||
let mut plugin_phase = false;
|
_ => return,
|
||||||
|
|
||||||
for attr in vi.attrs.iter().filter(|a| a.check_name("phase")) {
|
|
||||||
let phases = attr.meta_item_list().unwrap_or(&[]);
|
|
||||||
if attr::contains_name(phases, "plugin") {
|
|
||||||
plugin_phase = true;
|
|
||||||
}
|
}
|
||||||
if attr::contains_name(phases, "syntax") {
|
|
||||||
plugin_phase = true;
|
// Parse the attributes relating to macro / plugin loading.
|
||||||
self.sess.span_warn(attr.span,
|
let mut plugin_attr = None;
|
||||||
"phase(syntax) is a deprecated synonym for phase(plugin)");
|
let mut macro_selection = Some(HashSet::new()); // None => load all
|
||||||
|
let mut reexport = HashSet::new();
|
||||||
|
for attr in vi.attrs.iter() {
|
||||||
|
let mut used = true;
|
||||||
|
match attr.name().get() {
|
||||||
|
"phase" => {
|
||||||
|
self.sess.span_err(attr.span, "#[phase] is deprecated; use \
|
||||||
|
#[macro_use], #[plugin], and/or #[no_link]");
|
||||||
|
}
|
||||||
|
"plugin" => {
|
||||||
|
if plugin_attr.is_some() {
|
||||||
|
self.sess.span_err(attr.span, "#[plugin] specified multiple times");
|
||||||
|
}
|
||||||
|
plugin_attr = Some(attr.node.value.clone());
|
||||||
|
}
|
||||||
|
"macro_use" => {
|
||||||
|
let names = attr.meta_item_list();
|
||||||
|
if names.is_none() {
|
||||||
|
// no names => load all
|
||||||
|
macro_selection = None;
|
||||||
|
}
|
||||||
|
if let (Some(sel), Some(names)) = (macro_selection.as_mut(), names) {
|
||||||
|
for name in names.iter() {
|
||||||
|
if let ast::MetaWord(ref name) = name.node {
|
||||||
|
sel.insert(name.clone());
|
||||||
|
} else {
|
||||||
|
self.sess.span_err(name.span, "bad macro import");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"macro_reexport" => {
|
||||||
|
let names = match attr.meta_item_list() {
|
||||||
|
Some(names) => names,
|
||||||
|
None => {
|
||||||
|
self.sess.span_err(attr.span, "bad macro reexport");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for name in names.iter() {
|
||||||
|
if let ast::MetaWord(ref name) = name.node {
|
||||||
|
reexport.insert(name.clone());
|
||||||
|
} else {
|
||||||
|
self.sess.span_err(name.span, "bad macro reexport");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => used = false,
|
||||||
|
}
|
||||||
|
if used {
|
||||||
|
attr::mark_used(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !plugin_phase { return; }
|
let mut macros = vec![];
|
||||||
|
let mut registrar = None;
|
||||||
|
|
||||||
let PluginMetadata { macros, lib, registrar_symbol } =
|
let load_macros = match macro_selection.as_ref() {
|
||||||
self.reader.read_plugin_metadata(vi);
|
Some(sel) => sel.len() != 0 || reexport.len() != 0,
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
let load_registrar = plugin_attr.is_some();
|
||||||
|
|
||||||
self.plugins.macros.push(ExportedMacros {
|
if load_macros && !self.span_whitelist.contains(&vi.span) {
|
||||||
crate_name: name,
|
self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \
|
||||||
macros: macros,
|
the crate root");
|
||||||
|
}
|
||||||
|
|
||||||
|
if load_macros || load_registrar {
|
||||||
|
let pmd = self.reader.read_plugin_metadata(vi);
|
||||||
|
if load_macros {
|
||||||
|
macros = pmd.exported_macros();
|
||||||
|
}
|
||||||
|
if load_registrar {
|
||||||
|
registrar = pmd.plugin_registrar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for mut def in macros.into_iter() {
|
||||||
|
let name = token::get_ident(def.ident);
|
||||||
|
def.use_locally = match macro_selection.as_ref() {
|
||||||
|
None => true,
|
||||||
|
Some(sel) => sel.contains(&name),
|
||||||
|
};
|
||||||
|
def.export = reexport.contains(&name);
|
||||||
|
self.plugins.macros.push(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((lib, symbol)) = registrar {
|
||||||
|
let fun = self.dylink_registrar(vi, lib, symbol);
|
||||||
|
self.plugins.registrars.push(PluginRegistrar {
|
||||||
|
fun: fun,
|
||||||
|
args: plugin_attr.unwrap(),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match (lib, registrar_symbol) {
|
|
||||||
(Some(lib), Some(symbol))
|
|
||||||
=> self.dylink_registrar(vi, lib, symbol),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn visit_mac(&mut self, _: &ast::Mac) {
|
fn visit_mac(&mut self, _: &ast::Mac) {
|
||||||
// bummer... can't see plugins inside macros.
|
// bummer... can't see plugins inside macros.
|
||||||
// do nothing.
|
// do nothing.
|
||||||
|
@ -132,7 +211,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
|
||||||
|
|
||||||
impl<'a> PluginLoader<'a> {
|
impl<'a> PluginLoader<'a> {
|
||||||
// Dynamically link a registrar function into the compiler process.
|
// Dynamically link a registrar function into the compiler process.
|
||||||
fn dylink_registrar(&mut self, vi: &ast::ViewItem, path: Path, symbol: String) {
|
fn dylink_registrar(&mut self,
|
||||||
|
vi: &ast::ViewItem,
|
||||||
|
path: Path,
|
||||||
|
symbol: String) -> PluginRegistrarFun {
|
||||||
// Make sure the path contains a / or the linker will search for it.
|
// Make sure the path contains a / or the linker will search for it.
|
||||||
let path = os::make_absolute(&path).unwrap();
|
let path = os::make_absolute(&path).unwrap();
|
||||||
|
|
||||||
|
@ -154,13 +236,12 @@ impl<'a> PluginLoader<'a> {
|
||||||
Err(err) => self.sess.span_fatal(vi.span, err[])
|
Err(err) => self.sess.span_fatal(vi.span, err[])
|
||||||
};
|
};
|
||||||
|
|
||||||
self.plugins.registrars.push(registrar);
|
|
||||||
|
|
||||||
// Intentionally leak the dynamic library. We can't ever unload it
|
// Intentionally leak the dynamic library. We can't ever unload it
|
||||||
// since the library can make things that will live arbitrarily long
|
// since the library can make things that will live arbitrarily long
|
||||||
// (e.g. an @-box cycle or a task).
|
// (e.g. an @-box cycle or a task).
|
||||||
mem::forget(lib);
|
mem::forget(lib);
|
||||||
|
|
||||||
|
registrar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,14 +43,14 @@
|
||||||
//! To use a plugin while compiling another crate:
|
//! To use a plugin while compiling another crate:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! #![feature(phase)]
|
//! #![feature(plugin)]
|
||||||
//!
|
//!
|
||||||
//! #[phase(plugin)]
|
//! #[plugin]
|
||||||
//! extern crate myplugin;
|
//! extern crate myplugin;
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! If you also need the plugin crate available at runtime, use
|
//! If you don't need the plugin crate available at runtime, use
|
||||||
//! `phase(plugin, link)`.
|
//! `#[no_link]` as well.
|
||||||
//!
|
//!
|
||||||
//! See [the compiler plugin guide](../../guide-plugin.html)
|
//! See [the compiler plugin guide](../../guide-plugin.html)
|
||||||
//! for more examples.
|
//! for more examples.
|
||||||
|
|
|
@ -11,12 +11,14 @@
|
||||||
//! Used by plugin crates to tell `rustc` about the plugins they provide.
|
//! Used by plugin crates to tell `rustc` about the plugins they provide.
|
||||||
|
|
||||||
use lint::{LintPassObject, LintId, Lint};
|
use lint::{LintPassObject, LintId, Lint};
|
||||||
|
use session::Session;
|
||||||
|
|
||||||
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
||||||
use syntax::ext::base::{IdentTT, LetSyntaxTT, Decorator, Modifier};
|
use syntax::ext::base::{IdentTT, Decorator, Modifier, MacroRulesTT};
|
||||||
use syntax::ext::base::{MacroExpanderFn};
|
use syntax::ext::base::{MacroExpanderFn};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
use syntax::ptr::P;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -29,7 +31,14 @@ use std::collections::HashMap;
|
||||||
/// This struct has public fields and other methods for use by `rustc`
|
/// This struct has public fields and other methods for use by `rustc`
|
||||||
/// itself. They are not documented here, and plugin authors should
|
/// itself. They are not documented here, and plugin authors should
|
||||||
/// not use them.
|
/// not use them.
|
||||||
pub struct Registry {
|
pub struct Registry<'a> {
|
||||||
|
/// Compiler session. Useful if you want to emit diagnostic messages
|
||||||
|
/// from the plugin registrar.
|
||||||
|
pub sess: &'a Session,
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub args_hidden: Option<P<ast::MetaItem>>,
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub krate_span: Span,
|
pub krate_span: Span,
|
||||||
|
|
||||||
|
@ -43,10 +52,12 @@ pub struct Registry {
|
||||||
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registry {
|
impl<'a> Registry<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn new(krate: &ast::Crate) -> Registry {
|
pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
|
||||||
Registry {
|
Registry {
|
||||||
|
sess: sess,
|
||||||
|
args_hidden: None,
|
||||||
krate_span: krate.span,
|
krate_span: krate.span,
|
||||||
syntax_exts: vec!(),
|
syntax_exts: vec!(),
|
||||||
lint_passes: vec!(),
|
lint_passes: vec!(),
|
||||||
|
@ -54,6 +65,14 @@ impl Registry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `#[plugin]` attribute used to load this plugin.
|
||||||
|
///
|
||||||
|
/// This gives access to arguments passed via `#[plugin=...]` or
|
||||||
|
/// `#[plugin(...)]`.
|
||||||
|
pub fn args<'b>(&'b self) -> &'b P<ast::MetaItem> {
|
||||||
|
self.args_hidden.as_ref().expect("args not set")
|
||||||
|
}
|
||||||
|
|
||||||
/// Register a syntax extension of any kind.
|
/// Register a syntax extension of any kind.
|
||||||
///
|
///
|
||||||
/// This is the most general hook into `libsyntax`'s expansion behavior.
|
/// This is the most general hook into `libsyntax`'s expansion behavior.
|
||||||
|
@ -63,8 +82,11 @@ impl Registry {
|
||||||
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
|
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
|
||||||
Decorator(ext) => Decorator(ext),
|
Decorator(ext) => Decorator(ext),
|
||||||
Modifier(ext) => Modifier(ext),
|
Modifier(ext) => Modifier(ext),
|
||||||
// there's probably a nicer way to signal this:
|
|
||||||
LetSyntaxTT(_, _) => panic!("can't register a new LetSyntax!"),
|
MacroRulesTT => {
|
||||||
|
self.sess.err("plugin tried to register a new MacroRulesTT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,14 @@
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(old_orphan_check)]
|
#![feature(old_orphan_check)]
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)]
|
#[phase(plugin, link)]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
|
|
||||||
|
|
|
@ -346,12 +346,12 @@ impl Engine256State {
|
||||||
|
|
||||||
// Sha-512 and Sha-256 use basically the same calculations which are implemented
|
// Sha-512 and Sha-256 use basically the same calculations which are implemented
|
||||||
// by these macros. Inlining the calculations seems to result in better generated code.
|
// by these macros. Inlining the calculations seems to result in better generated code.
|
||||||
macro_rules! schedule_round( ($t:expr) => (
|
macro_rules! schedule_round { ($t:expr) => (
|
||||||
w[$t] = sigma1(w[$t - 2]) + w[$t - 7] + sigma0(w[$t - 15]) + w[$t - 16];
|
w[$t] = sigma1(w[$t - 2]) + w[$t - 7] + sigma0(w[$t - 15]) + w[$t - 16];
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
macro_rules! sha2_round(
|
macro_rules! sha2_round {
|
||||||
($A:ident, $B:ident, $C:ident, $D:ident,
|
($A:ident, $B:ident, $C:ident, $D:ident,
|
||||||
$E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
|
$E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
|
||||||
{
|
{
|
||||||
|
@ -360,7 +360,7 @@ impl Engine256State {
|
||||||
$H += sum0($A) + maj($A, $B, $C);
|
$H += sum0($A) + maj($A, $B, $C);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
read_u32v_be(w.slice_mut(0, 16), data);
|
read_u32v_be(w.slice_mut(0, 16), data);
|
||||||
|
|
||||||
|
|
|
@ -327,11 +327,11 @@ mod svh_visitor {
|
||||||
|
|
||||||
impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> {
|
impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> {
|
||||||
|
|
||||||
fn visit_mac(&mut self, macro: &Mac) {
|
fn visit_mac(&mut self, mac: &Mac) {
|
||||||
// macro invocations, namely macro_rules definitions,
|
// macro invocations, namely macro_rules definitions,
|
||||||
// *can* appear as items, even in the expanded crate AST.
|
// *can* appear as items, even in the expanded crate AST.
|
||||||
|
|
||||||
if macro_name(macro).get() == "macro_rules" {
|
if macro_name(mac).get() == "macro_rules" {
|
||||||
// Pretty-printing definition to a string strips out
|
// Pretty-printing definition to a string strips out
|
||||||
// surface artifacts (currently), such as the span
|
// surface artifacts (currently), such as the span
|
||||||
// information, yielding a content-based hash.
|
// information, yielding a content-based hash.
|
||||||
|
@ -341,7 +341,7 @@ mod svh_visitor {
|
||||||
// trees might be faster. Implementing this is far
|
// trees might be faster. Implementing this is far
|
||||||
// easier in short term.
|
// easier in short term.
|
||||||
let macro_defn_as_string = pprust::to_string(|pp_state| {
|
let macro_defn_as_string = pprust::to_string(|pp_state| {
|
||||||
pp_state.print_mac(macro, token::Paren)
|
pp_state.print_mac(mac, token::Paren)
|
||||||
});
|
});
|
||||||
macro_defn_as_string.hash(self.st);
|
macro_defn_as_string.hash(self.st);
|
||||||
} else {
|
} else {
|
||||||
|
@ -349,14 +349,14 @@ mod svh_visitor {
|
||||||
// invocation at this stage except `macro_rules!`.
|
// invocation at this stage except `macro_rules!`.
|
||||||
panic!("reached macro somehow: {}",
|
panic!("reached macro somehow: {}",
|
||||||
pprust::to_string(|pp_state| {
|
pprust::to_string(|pp_state| {
|
||||||
pp_state.print_mac(macro, token::Paren)
|
pp_state.print_mac(mac, token::Paren)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
visit::walk_mac(self, macro);
|
visit::walk_mac(self, mac);
|
||||||
|
|
||||||
fn macro_name(macro: &Mac) -> token::InternedString {
|
fn macro_name(mac: &Mac) -> token::InternedString {
|
||||||
match ¯o.node {
|
match &mac.node {
|
||||||
&MacInvocTT(ref path, ref _tts, ref _stx_ctxt) => {
|
&MacInvocTT(ref path, ref _tts, ref _stx_ctxt) => {
|
||||||
let s = path.segments[];
|
let s = path.segments[];
|
||||||
assert_eq!(s.len(), 1);
|
assert_eq!(s.len(), 1);
|
||||||
|
|
|
@ -239,7 +239,7 @@ impl Target {
|
||||||
options: Default::default(),
|
options: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! key (
|
macro_rules! key {
|
||||||
($key_name:ident) => ( {
|
($key_name:ident) => ( {
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
obj.find(name[]).map(|o| o.as_string()
|
obj.find(name[]).map(|o| o.as_string()
|
||||||
|
@ -257,7 +257,7 @@ impl Target {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
);
|
}
|
||||||
|
|
||||||
key!(cpu);
|
key!(cpu);
|
||||||
key!(linker);
|
key!(linker);
|
||||||
|
@ -305,7 +305,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this would use a match if stringify! were allowed in pattern position
|
// this would use a match if stringify! were allowed in pattern position
|
||||||
macro_rules! load_specific (
|
macro_rules! load_specific {
|
||||||
( $($name:ident),+ ) => (
|
( $($name:ident),+ ) => (
|
||||||
{
|
{
|
||||||
let target = target.replace("-", "_");
|
let target = target.replace("-", "_");
|
||||||
|
@ -326,7 +326,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
load_specific!(
|
load_specific!(
|
||||||
x86_64_unknown_linux_gnu,
|
x86_64_unknown_linux_gnu,
|
||||||
|
|
|
@ -39,15 +39,6 @@ use syntax::visit;
|
||||||
use syntax::visit::{Visitor, FnKind};
|
use syntax::visit::{Visitor, FnKind};
|
||||||
use syntax::ast::{FnDecl, Block, NodeId};
|
use syntax::ast::{FnDecl, Block, NodeId};
|
||||||
|
|
||||||
macro_rules! if_ok {
|
|
||||||
($inp: expr) => (
|
|
||||||
match $inp {
|
|
||||||
Ok(v) => { v }
|
|
||||||
Err(e) => { return Err(e); }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod doc;
|
pub mod doc;
|
||||||
|
|
||||||
pub mod check_loans;
|
pub mod check_loans;
|
||||||
|
|
|
@ -24,8 +24,21 @@
|
||||||
#![feature(old_orphan_check)]
|
#![feature(old_orphan_check)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
#[phase(plugin, link)] extern crate log;
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)] extern crate syntax;
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
|
// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
|
||||||
// refers to the borrowck-specific graphviz adapter traits.
|
// refers to the borrowck-specific graphviz adapter traits.
|
||||||
|
|
|
@ -12,7 +12,7 @@ use rustc::session::Session;
|
||||||
use rustc::session::config::{self, Input, OutputFilenames};
|
use rustc::session::config::{self, Input, OutputFilenames};
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
use rustc::metadata::creader;
|
use rustc::metadata::creader::CrateReader;
|
||||||
use rustc::middle::{stability, ty, reachable};
|
use rustc::middle::{stability, ty, reachable};
|
||||||
use rustc::middle::dependency_format;
|
use rustc::middle::dependency_format;
|
||||||
use rustc::middle;
|
use rustc::middle;
|
||||||
|
@ -182,7 +182,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||||
// strip before expansion to allow macros to depend on
|
// strip before expansion to allow macros to depend on
|
||||||
// configuration variables e.g/ in
|
// configuration variables e.g/ in
|
||||||
//
|
//
|
||||||
// #[macro_escape] #[cfg(foo)]
|
// #[macro_use] #[cfg(foo)]
|
||||||
// mod bar { macro_rules! baz!(() => {{}}) }
|
// mod bar { macro_rules! baz!(() => {{}}) }
|
||||||
//
|
//
|
||||||
// baz! should not use this definition unless foo is enabled.
|
// baz! should not use this definition unless foo is enabled.
|
||||||
|
@ -216,9 +216,9 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||||
= time(time_passes, "plugin loading", (), |_|
|
= time(time_passes, "plugin loading", (), |_|
|
||||||
plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
|
plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
|
||||||
|
|
||||||
let mut registry = Registry::new(&krate);
|
let mut registry = Registry::new(sess, &krate);
|
||||||
|
|
||||||
time(time_passes, "plugin registration", (), |_| {
|
time(time_passes, "plugin registration", registrars, |registrars| {
|
||||||
if sess.features.borrow().rustc_diagnostic_macros {
|
if sess.features.borrow().rustc_diagnostic_macros {
|
||||||
registry.register_macro("__diagnostic_used",
|
registry.register_macro("__diagnostic_used",
|
||||||
diagnostics::plugin::expand_diagnostic_used);
|
diagnostics::plugin::expand_diagnostic_used);
|
||||||
|
@ -228,8 +228,9 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||||
diagnostics::plugin::expand_build_diagnostic_array);
|
diagnostics::plugin::expand_build_diagnostic_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ®istrar in registrars.iter() {
|
for registrar in registrars.into_iter() {
|
||||||
registrar(&mut registry);
|
registry.args_hidden = Some(registrar.args);
|
||||||
|
(registrar.fun)(&mut registry);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -351,7 +352,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
|
||||||
let krate = ast_map.krate();
|
let krate = ast_map.krate();
|
||||||
|
|
||||||
time(time_passes, "external crate/lib resolution", (), |_|
|
time(time_passes, "external crate/lib resolution", (), |_|
|
||||||
creader::read_crates(&sess, krate));
|
CrateReader::new(&sess).read_crates(krate));
|
||||||
|
|
||||||
let lang_items = time(time_passes, "language item collection", (), |_|
|
let lang_items = time(time_passes, "language item collection", (), |_|
|
||||||
middle::lang_items::collect_language_items(krate, &sess));
|
middle::lang_items::collect_language_items(krate, &sess));
|
||||||
|
|
|
@ -39,11 +39,25 @@ extern crate rustc_borrowck;
|
||||||
extern crate rustc_resolve;
|
extern crate rustc_resolve;
|
||||||
extern crate rustc_trans;
|
extern crate rustc_trans;
|
||||||
extern crate rustc_typeck;
|
extern crate rustc_typeck;
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
#[phase(plugin, link)] extern crate syntax;
|
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate "rustc_llvm" as llvm;
|
extern crate "rustc_llvm" as llvm;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
pub use syntax::diagnostic;
|
pub use syntax::diagnostic;
|
||||||
|
|
||||||
use rustc_trans::back::link;
|
use rustc_trans::back::link;
|
||||||
|
|
|
@ -484,8 +484,8 @@ impl fold::Folder for ReplaceBodyWithLoop {
|
||||||
|
|
||||||
// in general the pretty printer processes unexpanded code, so
|
// in general the pretty printer processes unexpanded code, so
|
||||||
// we override the default `fold_mac` method which panics.
|
// we override the default `fold_mac` method which panics.
|
||||||
fn fold_mac(&mut self, _macro: ast::Mac) -> ast::Mac {
|
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||||
fold::noop_fold_mac(_macro, self)
|
fold::noop_fold_mac(mac, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,21 @@
|
||||||
#![feature(associated_types)]
|
#![feature(associated_types)]
|
||||||
#![feature(old_orphan_check)]
|
#![feature(old_orphan_check)]
|
||||||
|
|
||||||
#[phase(plugin, link)] extern crate log;
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)] extern crate syntax;
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,25 @@ extern crate graphviz;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
#[phase(plugin, link)] extern crate syntax;
|
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate "rustc_llvm" as llvm;
|
extern crate "rustc_llvm" as llvm;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
pub use rustc::session;
|
pub use rustc::session;
|
||||||
pub use rustc::metadata;
|
pub use rustc::metadata;
|
||||||
pub use rustc::middle;
|
pub use rustc::middle;
|
||||||
|
|
|
@ -736,7 +736,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {
|
fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {
|
||||||
macro_rules! ifn (
|
macro_rules! ifn {
|
||||||
($name:expr fn() -> $ret:expr) => (
|
($name:expr fn() -> $ret:expr) => (
|
||||||
if *key == $name {
|
if *key == $name {
|
||||||
let f = base::decl_cdecl_fn(
|
let f = base::decl_cdecl_fn(
|
||||||
|
@ -754,10 +754,10 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
|
||||||
return Some(f);
|
return Some(f);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
macro_rules! mk_struct (
|
macro_rules! mk_struct {
|
||||||
($($field_ty:expr),*) => (Type::struct_(ccx, &[$($field_ty),*], false))
|
($($field_ty:expr),*) => (Type::struct_(ccx, &[$($field_ty),*], false))
|
||||||
);
|
}
|
||||||
|
|
||||||
let i8p = Type::i8p(ccx);
|
let i8p = Type::i8p(ccx);
|
||||||
let void = Type::void(ccx);
|
let void = Type::void(ccx);
|
||||||
|
@ -878,7 +878,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
|
||||||
// Some intrinsics were introduced in later versions of LLVM, but they have
|
// Some intrinsics were introduced in later versions of LLVM, but they have
|
||||||
// fallbacks in libc or libm and such. Currently, all of these intrinsics
|
// fallbacks in libc or libm and such. Currently, all of these intrinsics
|
||||||
// were introduced in LLVM 3.4, so we case on that.
|
// were introduced in LLVM 3.4, so we case on that.
|
||||||
macro_rules! compatible_ifn (
|
macro_rules! compatible_ifn {
|
||||||
($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => (
|
($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => (
|
||||||
if unsafe { llvm::LLVMVersionMinor() >= 4 } {
|
if unsafe { llvm::LLVMVersionMinor() >= 4 } {
|
||||||
// The `if key == $name` is already in ifn!
|
// The `if key == $name` is already in ifn!
|
||||||
|
@ -891,7 +891,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
|
||||||
return Some(f);
|
return Some(f);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
compatible_ifn!("llvm.copysign.f32", copysignf(t_f32, t_f32) -> t_f32);
|
compatible_ifn!("llvm.copysign.f32", copysignf(t_f32, t_f32) -> t_f32);
|
||||||
compatible_ifn!("llvm.copysign.f64", copysign(t_f64, t_f64) -> t_f64);
|
compatible_ifn!("llvm.copysign.f64", copysign(t_f64, t_f64) -> t_f64);
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
macro_rules! unpack_datum {
|
macro_rules! unpack_datum {
|
||||||
($bcx: ident, $inp: expr) => (
|
($bcx: ident, $inp: expr) => (
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,8 +16,11 @@ pub use self::base::trans_crate;
|
||||||
pub use self::context::CrateContext;
|
pub use self::context::CrateContext;
|
||||||
pub use self::common::gensym_name;
|
pub use self::common::gensym_name;
|
||||||
|
|
||||||
mod doc;
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
|
mod doc;
|
||||||
mod inline;
|
mod inline;
|
||||||
mod monomorphize;
|
mod monomorphize;
|
||||||
mod controlflow;
|
mod controlflow;
|
||||||
|
|
|
@ -77,8 +77,21 @@ This API is completely unstable and subject to change.
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
#[phase(plugin, link)] extern crate log;
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)] extern crate syntax;
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
extern crate arena;
|
extern crate arena;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
|
|
|
@ -166,6 +166,9 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special macro vars are like keywords
|
||||||
|
token::SpecialVarNt(_) => "kw-2",
|
||||||
|
|
||||||
token::Lifetime(..) => "lifetime",
|
token::Lifetime(..) => "lifetime",
|
||||||
token::DocComment(..) => "doccomment",
|
token::DocComment(..) => "doccomment",
|
||||||
token::Underscore | token::Eof | token::Interpolated(..) |
|
token::Underscore | token::Eof | token::Interpolated(..) |
|
||||||
|
|
|
@ -32,7 +32,14 @@ extern crate rustc_driver;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate "test" as testing;
|
extern crate "test" as testing;
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
extern crate "serialize" as rustc_serialize; // used by deriving
|
extern crate "serialize" as rustc_serialize; // used by deriving
|
||||||
|
|
||||||
|
@ -49,11 +56,13 @@ use rustc::session::search_paths::SearchPaths;
|
||||||
// reexported from `clean` so it can be easily updated with the mod itself
|
// reexported from `clean` so it can be easily updated with the mod itself
|
||||||
pub use clean::SCHEMA_VERSION;
|
pub use clean::SCHEMA_VERSION;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
pub mod externalfiles;
|
||||||
|
|
||||||
pub mod clean;
|
pub mod clean;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod doctree;
|
pub mod doctree;
|
||||||
#[macro_escape]
|
|
||||||
pub mod externalfiles;
|
|
||||||
pub mod fold;
|
pub mod fold;
|
||||||
pub mod html {
|
pub mod html {
|
||||||
pub mod highlight;
|
pub mod highlight;
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||||
None);
|
None);
|
||||||
// attach the crate's exported macros to the top-level module:
|
// attach the crate's exported macros to the top-level module:
|
||||||
self.module.macros = krate.exported_macros.iter()
|
self.module.macros = krate.exported_macros.iter()
|
||||||
.map(|it| self.visit_macro(&**it)).collect();
|
.map(|def| self.visit_macro(def)).collect();
|
||||||
self.module.is_crate = true;
|
self.module.is_crate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,13 +363,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert each exported_macro into a doc item
|
// convert each exported_macro into a doc item
|
||||||
fn visit_macro(&self, item: &ast::Item) -> Macro {
|
fn visit_macro(&self, def: &ast::MacroDef) -> Macro {
|
||||||
Macro {
|
Macro {
|
||||||
id: item.id,
|
id: def.id,
|
||||||
attrs: item.attrs.clone(),
|
attrs: def.attrs.clone(),
|
||||||
name: item.ident,
|
name: def.ident,
|
||||||
whence: item.span,
|
whence: def.span,
|
||||||
stab: self.stability(item.id),
|
stab: self.stability(def.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,14 @@ Core encoding and decoding interfaces.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
#[phase(plugin, link)]
|
#[phase(plugin, link)]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
extern crate unicode;
|
extern crate unicode;
|
||||||
|
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![experimental]
|
#![experimental]
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
//! A typesafe bitmask flag generator.
|
//! A typesafe bitmask flag generator.
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,9 @@ use hash::{Hash, Hasher, RandomSipHasher};
|
||||||
use iter::{Iterator, IteratorExt, FromIterator, Map, Chain, Extend};
|
use iter::{Iterator, IteratorExt, FromIterator, Map, Chain, Extend};
|
||||||
use ops::{BitOr, BitAnd, BitXor, Sub};
|
use ops::{BitOr, BitAnd, BitXor, Sub};
|
||||||
use option::Option::{Some, None, self};
|
use option::Option::{Some, None, self};
|
||||||
use result::Result::{Ok, Err};
|
|
||||||
|
// NOTE: for old macros; remove after the next snapshot
|
||||||
|
#[cfg(stage0)] use result::Result::{Ok, Err};
|
||||||
|
|
||||||
use super::map::{self, HashMap, Keys, INITIAL_CAPACITY};
|
use super::map::{self, HashMap, Keys, INITIAL_CAPACITY};
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,14 @@ use iter::{IteratorExt, ExactSizeIterator};
|
||||||
use ops::Drop;
|
use ops::Drop;
|
||||||
use option::Option;
|
use option::Option;
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
use result::Result::{Ok, Err};
|
use result::Result::Ok;
|
||||||
use slice::{SliceExt};
|
use slice::{SliceExt};
|
||||||
use slice;
|
use slice;
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
|
|
||||||
|
// NOTE: for old macros; remove after the next snapshot
|
||||||
|
#[cfg(stage0)] use result::Result::Err;
|
||||||
|
|
||||||
/// Wraps a Reader and buffers input from it
|
/// Wraps a Reader and buffers input from it
|
||||||
///
|
///
|
||||||
/// It can be excessively inefficient to work directly with a `Reader`. For
|
/// It can be excessively inefficient to work directly with a `Reader`. For
|
||||||
|
|
|
@ -282,10 +282,13 @@ pub mod net;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod stdio;
|
pub mod stdio;
|
||||||
pub mod test;
|
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
pub mod test;
|
||||||
|
|
||||||
/// The default buffer size for various I/O operations
|
/// The default buffer size for various I/O operations
|
||||||
// libuv recommends 64k buffers to maximize throughput
|
// libuv recommends 64k buffers to maximize throughput
|
||||||
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
|
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
//! Various utility functions useful for writing I/O tests
|
//! Various utility functions useful for writing I/O tests
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
|
|
|
@ -117,13 +117,36 @@
|
||||||
|
|
||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
|
||||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
#[cfg(all(test, stage0))]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(stage0)))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
#[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq,
|
||||||
|
unreachable, unimplemented, write, writeln)]
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate "collections" as core_collections;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
#[macro_reexport(vec)]
|
||||||
|
extern crate "collections" as core_collections;
|
||||||
|
|
||||||
|
extern crate "rand" as core_rand;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate unicode;
|
extern crate unicode;
|
||||||
extern crate core;
|
|
||||||
extern crate "collections" as core_collections;
|
|
||||||
extern crate "rand" as core_rand;
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
// Make std testable by not duplicating lang items. See #2912
|
// Make std testable by not duplicating lang items. See #2912
|
||||||
|
@ -167,7 +190,18 @@ pub use unicode::char;
|
||||||
|
|
||||||
/* Exported macros */
|
/* Exported macros */
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
pub mod macros_stage0;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
pub mod bitflags;
|
pub mod bitflags;
|
||||||
|
|
||||||
mod rtdeps;
|
mod rtdeps;
|
||||||
|
@ -179,9 +213,20 @@ pub mod prelude;
|
||||||
|
|
||||||
/* Primitive types */
|
/* Primitive types */
|
||||||
|
|
||||||
#[path = "num/float_macros.rs"] mod float_macros;
|
#[path = "num/float_macros.rs"]
|
||||||
#[path = "num/int_macros.rs"] mod int_macros;
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
#[path = "num/uint_macros.rs"] mod uint_macros;
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
mod float_macros;
|
||||||
|
|
||||||
|
#[path = "num/int_macros.rs"]
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
mod int_macros;
|
||||||
|
|
||||||
|
#[path = "num/uint_macros.rs"]
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
mod uint_macros;
|
||||||
|
|
||||||
#[path = "num/int.rs"] pub mod int;
|
#[path = "num/int.rs"] pub mod int;
|
||||||
#[path = "num/i8.rs"] pub mod i8;
|
#[path = "num/i8.rs"] pub mod i8;
|
||||||
|
@ -210,6 +255,10 @@ pub mod num;
|
||||||
|
|
||||||
pub mod thread_local; // first for macros
|
pub mod thread_local; // first for macros
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
|
pub mod thread_local;
|
||||||
|
|
||||||
pub mod dynamic_lib;
|
pub mod dynamic_lib;
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
//! library.
|
//! library.
|
||||||
|
|
||||||
#![experimental]
|
#![experimental]
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
/// The entry point for panic of Rust tasks.
|
/// The entry point for panic of Rust tasks.
|
||||||
///
|
///
|
||||||
|
@ -246,34 +245,6 @@ macro_rules! format {
|
||||||
($($arg:tt)*) => (::std::fmt::format(format_args!($($arg)*)))
|
($($arg:tt)*) => (::std::fmt::format(format_args!($($arg)*)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
|
|
||||||
/// See `std::fmt` for more information.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![allow(unused_must_use)]
|
|
||||||
///
|
|
||||||
/// let mut w = Vec::new();
|
|
||||||
/// write!(&mut w, "test");
|
|
||||||
/// write!(&mut w, "formatted {}", "arguments");
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
#[stable]
|
|
||||||
macro_rules! write {
|
|
||||||
($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to the `write!` macro, except that a newline is appended after
|
|
||||||
/// the message is written.
|
|
||||||
#[macro_export]
|
|
||||||
#[stable]
|
|
||||||
macro_rules! writeln {
|
|
||||||
($dst:expr, $fmt:expr $($arg:tt)*) => (
|
|
||||||
write!($dst, concat!($fmt, "\n") $($arg)*)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to the `println!` macro except that a newline is not printed at
|
/// Equivalent to the `println!` macro except that a newline is not printed at
|
||||||
/// the end of the message.
|
/// the end of the message.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -306,23 +277,15 @@ macro_rules! println {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! try {
|
macro_rules! try {
|
||||||
($expr:expr) => ({
|
($expr:expr) => ({
|
||||||
|
use $crate::result::Result::{Ok, Err};
|
||||||
|
|
||||||
match $expr {
|
match $expr {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(err) => return Err(::std::error::FromError::from_error(err))
|
Err(err) => return Err($crate::error::FromError::from_error(err)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `std::vec::Vec` containing the arguments.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! vec {
|
|
||||||
($($x:expr),*) => ({
|
|
||||||
let xs: ::std::boxed::Box<[_]> = box [$($x),*];
|
|
||||||
::std::slice::SliceExt::into_vec(xs)
|
|
||||||
});
|
|
||||||
($($x:expr,)*) => (vec![$($x),*])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A macro to select an event from a number of receivers.
|
/// A macro to select an event from a number of receivers.
|
||||||
///
|
///
|
||||||
/// This macro is used to wait for the first event to occur on a number of
|
/// This macro is used to wait for the first event to occur on a number of
|
||||||
|
@ -358,7 +321,7 @@ macro_rules! select {
|
||||||
(
|
(
|
||||||
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
|
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
|
||||||
) => ({
|
) => ({
|
||||||
use std::sync::mpsc::Select;
|
use $crate::sync::mpsc::Select;
|
||||||
let sel = Select::new();
|
let sel = Select::new();
|
||||||
$( let mut $rx = sel.handle(&$rx); )+
|
$( let mut $rx = sel.handle(&$rx); )+
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
648
src/libstd/macros_stage0.rs
Normal file
648
src/libstd/macros_stage0.rs
Normal file
|
@ -0,0 +1,648 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Standard library macros
|
||||||
|
//!
|
||||||
|
//! This modules contains a set of macros which are exported from the standard
|
||||||
|
//! library. Each macro is available for use when linking against the standard
|
||||||
|
//! library.
|
||||||
|
|
||||||
|
#![experimental]
|
||||||
|
|
||||||
|
/// The entry point for panic of Rust tasks.
|
||||||
|
///
|
||||||
|
/// This macro is used to inject panic into a Rust task, causing the task to
|
||||||
|
/// unwind and panic entirely. Each task's panic can be reaped as the
|
||||||
|
/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be
|
||||||
|
/// the value which is transmitted.
|
||||||
|
///
|
||||||
|
/// The multi-argument form of this macro panics with a string and has the
|
||||||
|
/// `format!` syntax for building a string.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```should_fail
|
||||||
|
/// # #![allow(unreachable_code)]
|
||||||
|
/// panic!();
|
||||||
|
/// panic!("this is a terrible mistake!");
|
||||||
|
/// panic!(4i); // panic with the value of 4 to be collected elsewhere
|
||||||
|
/// panic!("this is a {} {message}", "fancy", message = "message");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! panic {
|
||||||
|
() => ({
|
||||||
|
panic!("explicit panic")
|
||||||
|
});
|
||||||
|
($msg:expr) => ({
|
||||||
|
// static requires less code at runtime, more constant data
|
||||||
|
static _FILE_LINE: (&'static str, uint) = (file!(), line!());
|
||||||
|
::std::rt::begin_unwind($msg, &_FILE_LINE)
|
||||||
|
});
|
||||||
|
($fmt:expr, $($arg:tt)*) => ({
|
||||||
|
// The leading _'s are to avoid dead code warnings if this is
|
||||||
|
// used inside a dead function. Just `#[allow(dead_code)]` is
|
||||||
|
// insufficient, since the user may have
|
||||||
|
// `#[forbid(dead_code)]` and which cannot be overridden.
|
||||||
|
static _FILE_LINE: (&'static str, uint) = (file!(), line!());
|
||||||
|
::std::rt::begin_unwind_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE)
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure that a boolean expression is `true` at runtime.
|
||||||
|
///
|
||||||
|
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||||
|
/// evaluated to `true` at runtime.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // the panic message for these assertions is the stringified value of the
|
||||||
|
/// // expression given.
|
||||||
|
/// assert!(true);
|
||||||
|
/// # fn some_computation() -> bool { true }
|
||||||
|
/// assert!(some_computation());
|
||||||
|
///
|
||||||
|
/// // assert with a custom message
|
||||||
|
/// # let x = true;
|
||||||
|
/// assert!(x, "x wasn't true!");
|
||||||
|
/// # let a = 3i; let b = 27i;
|
||||||
|
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert {
|
||||||
|
($cond:expr) => (
|
||||||
|
if !$cond {
|
||||||
|
panic!(concat!("assertion failed: ", stringify!($cond)))
|
||||||
|
}
|
||||||
|
);
|
||||||
|
($cond:expr, $($arg:expr),+) => (
|
||||||
|
if !$cond {
|
||||||
|
panic!($($arg),+)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asserts that two expressions are equal to each other, testing equality in
|
||||||
|
/// both directions.
|
||||||
|
///
|
||||||
|
/// On panic, this macro will print the values of the expressions.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let a = 3i;
|
||||||
|
/// let b = 1i + 2i;
|
||||||
|
/// assert_eq!(a, b);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_eq {
|
||||||
|
($left:expr , $right:expr) => ({
|
||||||
|
match (&($left), &($right)) {
|
||||||
|
(left_val, right_val) => {
|
||||||
|
// check both directions of equality....
|
||||||
|
if !((*left_val == *right_val) &&
|
||||||
|
(*right_val == *left_val)) {
|
||||||
|
panic!("assertion failed: `(left == right) && (right == left)` \
|
||||||
|
(left: `{}`, right: `{}`)", *left_val, *right_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure that a boolean expression is `true` at runtime.
|
||||||
|
///
|
||||||
|
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||||
|
/// evaluated to `true` at runtime.
|
||||||
|
///
|
||||||
|
/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing
|
||||||
|
/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for
|
||||||
|
/// checks that are too expensive to be present in a release build but may be
|
||||||
|
/// helpful during development.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // the panic message for these assertions is the stringified value of the
|
||||||
|
/// // expression given.
|
||||||
|
/// debug_assert!(true);
|
||||||
|
/// # fn some_expensive_computation() -> bool { true }
|
||||||
|
/// debug_assert!(some_expensive_computation());
|
||||||
|
///
|
||||||
|
/// // assert with a custom message
|
||||||
|
/// # let x = true;
|
||||||
|
/// debug_assert!(x, "x wasn't true!");
|
||||||
|
/// # let a = 3i; let b = 27i;
|
||||||
|
/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug_assert {
|
||||||
|
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asserts that two expressions are equal to each other, testing equality in
|
||||||
|
/// both directions.
|
||||||
|
///
|
||||||
|
/// On panic, this macro will print the values of the expressions.
|
||||||
|
///
|
||||||
|
/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by
|
||||||
|
/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!`
|
||||||
|
/// useful for checks that are too expensive to be present in a release build
|
||||||
|
/// but may be helpful during development.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let a = 3i;
|
||||||
|
/// let b = 1i + 2i;
|
||||||
|
/// debug_assert_eq!(a, b);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug_assert_eq {
|
||||||
|
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A utility macro for indicating unreachable code.
|
||||||
|
///
|
||||||
|
/// This is useful any time that the compiler can't determine that some code is unreachable. For
|
||||||
|
/// example:
|
||||||
|
///
|
||||||
|
/// * Match arms with guard conditions.
|
||||||
|
/// * Loops that dynamically terminate.
|
||||||
|
/// * Iterators that dynamically terminate.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This will always panic.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Match arms:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn foo(x: Option<int>) {
|
||||||
|
/// match x {
|
||||||
|
/// Some(n) if n >= 0 => println!("Some(Non-negative)"),
|
||||||
|
/// Some(n) if n < 0 => println!("Some(Negative)"),
|
||||||
|
/// Some(_) => unreachable!(), // compile error if commented out
|
||||||
|
/// None => println!("None")
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Iterators:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
|
||||||
|
/// for i in std::iter::count(0_u32, 1) {
|
||||||
|
/// if 3*i < i { panic!("u32 overflow"); }
|
||||||
|
/// if x < 3*i { return i-1; }
|
||||||
|
/// }
|
||||||
|
/// unreachable!();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unreachable {
|
||||||
|
() => ({
|
||||||
|
panic!("internal error: entered unreachable code")
|
||||||
|
});
|
||||||
|
($msg:expr) => ({
|
||||||
|
unreachable!("{}", $msg)
|
||||||
|
});
|
||||||
|
($fmt:expr, $($arg:tt)*) => ({
|
||||||
|
panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A standardised placeholder for marking unfinished code. It panics with the
|
||||||
|
/// message `"not yet implemented"` when executed.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unimplemented {
|
||||||
|
() => (panic!("not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use the syntax described in `std::fmt` to create a value of type `String`.
|
||||||
|
/// See `std::fmt` for more information.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// format!("test");
|
||||||
|
/// format!("hello {}", "world!");
|
||||||
|
/// format!("x = {}, y = {y}", 10i, y = 30i);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
#[stable]
|
||||||
|
macro_rules! format {
|
||||||
|
($($arg:tt)*) => (::std::fmt::format(format_args!($($arg)*)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
|
||||||
|
/// See `std::fmt` for more information.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![allow(unused_must_use)]
|
||||||
|
///
|
||||||
|
/// let mut w = Vec::new();
|
||||||
|
/// write!(&mut w, "test");
|
||||||
|
/// write!(&mut w, "formatted {}", "arguments");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
#[stable]
|
||||||
|
macro_rules! write {
|
||||||
|
($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equivalent to the `write!` macro, except that a newline is appended after
|
||||||
|
/// the message is written.
|
||||||
|
#[macro_export]
|
||||||
|
#[stable]
|
||||||
|
macro_rules! writeln {
|
||||||
|
($dst:expr, $fmt:expr $($arg:tt)*) => (
|
||||||
|
write!($dst, concat!($fmt, "\n") $($arg)*)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equivalent to the `println!` macro except that a newline is not printed at
|
||||||
|
/// the end of the message.
|
||||||
|
#[macro_export]
|
||||||
|
#[stable]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => (::std::io::stdio::print_args(format_args!($($arg)*)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro for printing to a task's stdout handle.
|
||||||
|
///
|
||||||
|
/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
|
||||||
|
/// The syntax of this macro is the same as that used for `format!`. For more
|
||||||
|
/// information, see `std::fmt` and `std::io::stdio`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// println!("hello there!");
|
||||||
|
/// println!("format {} arguments", "some");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
#[stable]
|
||||||
|
macro_rules! println {
|
||||||
|
($($arg:tt)*) => (::std::io::stdio::println_args(format_args!($($arg)*)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper macro for unwrapping `Result` values while returning early with an
|
||||||
|
/// error if the value of the expression is `Err`. For more information, see
|
||||||
|
/// `std::io`.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! try {
|
||||||
|
($expr:expr) => ({
|
||||||
|
match $expr {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => return Err(::std::error::FromError::from_error(err))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `std::vec::Vec` containing the arguments.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! vec {
|
||||||
|
($($x:expr),*) => ({
|
||||||
|
let xs: ::std::boxed::Box<[_]> = box [$($x),*];
|
||||||
|
::std::slice::SliceExt::into_vec(xs)
|
||||||
|
});
|
||||||
|
($($x:expr,)*) => (vec![$($x),*])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro to select an event from a number of receivers.
|
||||||
|
///
|
||||||
|
/// This macro is used to wait for the first event to occur on a number of
|
||||||
|
/// receivers. It places no restrictions on the types of receivers given to
|
||||||
|
/// this macro, this can be viewed as a heterogeneous select.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::thread::Thread;
|
||||||
|
/// use std::sync::mpsc::channel;
|
||||||
|
///
|
||||||
|
/// let (tx1, rx1) = channel();
|
||||||
|
/// let (tx2, rx2) = channel();
|
||||||
|
/// # fn long_running_task() {}
|
||||||
|
/// # fn calculate_the_answer() -> int { 42i }
|
||||||
|
///
|
||||||
|
/// Thread::spawn(move|| { long_running_task(); tx1.send(()) }).detach();
|
||||||
|
/// Thread::spawn(move|| { tx2.send(calculate_the_answer()) }).detach();
|
||||||
|
///
|
||||||
|
/// select! (
|
||||||
|
/// _ = rx1.recv() => println!("the long running task finished first"),
|
||||||
|
/// answer = rx2.recv() => {
|
||||||
|
/// println!("the answer was: {}", answer.unwrap());
|
||||||
|
/// }
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// For more information about select, see the `std::sync::mpsc::Select` structure.
|
||||||
|
#[macro_export]
|
||||||
|
#[experimental]
|
||||||
|
macro_rules! select {
|
||||||
|
(
|
||||||
|
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
|
||||||
|
) => ({
|
||||||
|
use std::sync::mpsc::Select;
|
||||||
|
let sel = Select::new();
|
||||||
|
$( let mut $rx = sel.handle(&$rx); )+
|
||||||
|
unsafe {
|
||||||
|
$( $rx.add(); )+
|
||||||
|
}
|
||||||
|
let ret = sel.wait();
|
||||||
|
$( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
|
||||||
|
{ unreachable!() }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// When testing the standard library, we link to the liblog crate to get the
|
||||||
|
// logging macros. In doing so, the liblog crate was linked against the real
|
||||||
|
// version of libstd, and uses a different std::fmt module than the test crate
|
||||||
|
// uses. To get around this difference, we redefine the log!() macro here to be
|
||||||
|
// just a dumb version of what it should be.
|
||||||
|
#[cfg(test)]
|
||||||
|
macro_rules! log {
|
||||||
|
($lvl:expr, $($args:tt)*) => (
|
||||||
|
if log_enabled!($lvl) { println!($($args)*) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Built-in macros to the compiler itself.
|
||||||
|
///
|
||||||
|
/// These macros do not have any corresponding definition with a `macro_rules!`
|
||||||
|
/// macro, but are documented here. Their implementations can be found hardcoded
|
||||||
|
/// into libsyntax itself.
|
||||||
|
#[cfg(dox)]
|
||||||
|
pub mod builtin {
|
||||||
|
/// The core macro for formatted string creation & output.
|
||||||
|
///
|
||||||
|
/// This macro produces a value of type `fmt::Arguments`. This value can be
|
||||||
|
/// passed to the functions in `std::fmt` for performing useful functions.
|
||||||
|
/// All other formatting macros (`format!`, `write!`, `println!`, etc) are
|
||||||
|
/// proxied through this one.
|
||||||
|
///
|
||||||
|
/// For more information, see the documentation in `std::fmt`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use std::fmt;
|
||||||
|
///
|
||||||
|
/// let s = fmt::format(format_args!("hello {}", "world"));
|
||||||
|
/// assert_eq!(s, format!("hello {}", "world"));
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! format_args { ($fmt:expr $($args:tt)*) => ({
|
||||||
|
/* compiler built-in */
|
||||||
|
}) }
|
||||||
|
|
||||||
|
/// Inspect an environment variable at compile time.
|
||||||
|
///
|
||||||
|
/// This macro will expand to the value of the named environment variable at
|
||||||
|
/// compile time, yielding an expression of type `&'static str`.
|
||||||
|
///
|
||||||
|
/// If the environment variable is not defined, then a compilation error
|
||||||
|
/// will be emitted. To not emit a compile error, use the `option_env!`
|
||||||
|
/// macro instead.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let path: &'static str = env!("PATH");
|
||||||
|
/// println!("the $PATH variable at the time of compiling was: {}", path);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Optionally inspect an environment variable at compile time.
|
||||||
|
///
|
||||||
|
/// If the named environment variable is present at compile time, this will
|
||||||
|
/// expand into an expression of type `Option<&'static str>` whose value is
|
||||||
|
/// `Some` of the value of the environment variable. If the environment
|
||||||
|
/// variable is not present, then this will expand to `None`.
|
||||||
|
///
|
||||||
|
/// A compile time error is never emitted when using this macro regardless
|
||||||
|
/// of whether the environment variable is present or not.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let key: Option<&'static str> = option_env!("SECRET_KEY");
|
||||||
|
/// println!("the secret key might be: {}", key);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Concatenate literals into a static byte slice.
|
||||||
|
///
|
||||||
|
/// This macro takes any number of comma-separated literal expressions,
|
||||||
|
/// yielding an expression of type `&'static [u8]` which is the
|
||||||
|
/// concatenation (left to right) of all the literals in their byte format.
|
||||||
|
///
|
||||||
|
/// This extension currently only supports string literals, character
|
||||||
|
/// literals, and integers less than 256. The byte slice returned is the
|
||||||
|
/// utf8-encoding of strings and characters.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let rust = bytes!("r", 'u', "st", 255);
|
||||||
|
/// assert_eq!(rust[1], b'u');
|
||||||
|
/// assert_eq!(rust[4], 255);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! bytes { ($($e:expr),*) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Concatenate identifiers into one identifier.
|
||||||
|
///
|
||||||
|
/// This macro takes any number of comma-separated identifiers, and
|
||||||
|
/// concatenates them all into one, yielding an expression which is a new
|
||||||
|
/// identifier. Note that hygiene makes it such that this macro cannot
|
||||||
|
/// capture local variables, and macros are only allowed in item,
|
||||||
|
/// statement or expression position, meaning this macro may be difficult to
|
||||||
|
/// use in some situations.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(concat_idents)]
|
||||||
|
///
|
||||||
|
/// # fn main() {
|
||||||
|
/// fn foobar() -> int { 23 }
|
||||||
|
///
|
||||||
|
/// let f = concat_idents!(foo, bar);
|
||||||
|
/// println!("{}", f());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! concat_idents {
|
||||||
|
($($e:ident),*) => ({ /* compiler built-in */ })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Concatenates literals into a static string slice.
|
||||||
|
///
|
||||||
|
/// This macro takes any number of comma-separated literals, yielding an
|
||||||
|
/// expression of type `&'static str` which represents all of the literals
|
||||||
|
/// concatenated left-to-right.
|
||||||
|
///
|
||||||
|
/// Integer and floating point literals are stringified in order to be
|
||||||
|
/// concatenated.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let s = concat!("test", 10i, 'b', true);
|
||||||
|
/// assert_eq!(s, "test10btrue");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// A macro which expands to the line number on which it was invoked.
|
||||||
|
///
|
||||||
|
/// The expanded expression has type `uint`, and the returned line is not
|
||||||
|
/// the invocation of the `line!()` macro itself, but rather the first macro
|
||||||
|
/// invocation leading up to the invocation of the `line!()` macro.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let current_line = line!();
|
||||||
|
/// println!("defined on line: {}", current_line);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! line { () => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// A macro which expands to the column number on which it was invoked.
|
||||||
|
///
|
||||||
|
/// The expanded expression has type `uint`, and the returned column is not
|
||||||
|
/// the invocation of the `column!()` macro itself, but rather the first macro
|
||||||
|
/// invocation leading up to the invocation of the `column!()` macro.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let current_col = column!();
|
||||||
|
/// println!("defined on column: {}", current_col);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! column { () => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// A macro which expands to the file name from which it was invoked.
|
||||||
|
///
|
||||||
|
/// The expanded expression has type `&'static str`, and the returned file
|
||||||
|
/// is not the invocation of the `file!()` macro itself, but rather the
|
||||||
|
/// first macro invocation leading up to the invocation of the `file!()`
|
||||||
|
/// macro.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let this_file = file!();
|
||||||
|
/// println!("defined in file: {}", this_file);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! file { () => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// A macro which stringifies its argument.
|
||||||
|
///
|
||||||
|
/// This macro will yield an expression of type `&'static str` which is the
|
||||||
|
/// stringification of all the tokens passed to the macro. No restrictions
|
||||||
|
/// are placed on the syntax of the macro invocation itself.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let one_plus_one = stringify!(1 + 1);
|
||||||
|
/// assert_eq!(one_plus_one, "1 + 1");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Includes a utf8-encoded file as a string.
|
||||||
|
///
|
||||||
|
/// This macro will yield an expression of type `&'static str` which is the
|
||||||
|
/// contents of the filename specified. The file is located relative to the
|
||||||
|
/// current file (similarly to how modules are found),
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// let secret_key = include_str!("secret-key.ascii");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Includes a file as a byte slice.
|
||||||
|
///
|
||||||
|
/// This macro will yield an expression of type `&'static [u8]` which is
|
||||||
|
/// the contents of the filename specified. The file is located relative to
|
||||||
|
/// the current file (similarly to how modules are found),
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// let secret_key = include_bytes!("secret-key.bin");
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Deprecated alias for `include_bytes!()`.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! include_bin { ($file:expr) => ({ /* compiler built-in */}) }
|
||||||
|
|
||||||
|
/// Expands to a string that represents the current module path.
|
||||||
|
///
|
||||||
|
/// The current module path can be thought of as the hierarchy of modules
|
||||||
|
/// leading back up to the crate root. The first component of the path
|
||||||
|
/// returned is the name of the crate currently being compiled.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// mod test {
|
||||||
|
/// pub fn foo() {
|
||||||
|
/// assert!(module_path!().ends_with("test"));
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// test::foo();
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! module_path { () => ({ /* compiler built-in */ }) }
|
||||||
|
|
||||||
|
/// Boolean evaluation of configuration flags.
|
||||||
|
///
|
||||||
|
/// In addition to the `#[cfg]` attribute, this macro is provided to allow
|
||||||
|
/// boolean expression evaluation of configuration flags. This frequently
|
||||||
|
/// leads to less duplicated code.
|
||||||
|
///
|
||||||
|
/// The syntax given to this macro is the same syntax as the `cfg`
|
||||||
|
/// attribute.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let my_directory = if cfg!(windows) {
|
||||||
|
/// "windows-specific-directory"
|
||||||
|
/// } else {
|
||||||
|
/// "unix-directory"
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! cfg { ($cfg:tt) => ({ /* compiler built-in */ }) }
|
||||||
|
}
|
|
@ -9,7 +9,6 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![experimental]
|
#![experimental]
|
||||||
#![macro_escape]
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
|
|
||||||
macro_rules! assert_approx_eq {
|
macro_rules! assert_approx_eq {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![experimental]
|
#![experimental]
|
||||||
#![macro_escape]
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
|
|
||||||
macro_rules! int_module { ($T:ty) => (
|
macro_rules! int_module { ($T:ty) => (
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![experimental]
|
#![experimental]
|
||||||
#![macro_escape]
|
|
||||||
#![doc(hidden)]
|
#![doc(hidden)]
|
||||||
#![allow(unsigned_negation)]
|
#![allow(unsigned_negation)]
|
||||||
|
|
||||||
|
|
|
@ -535,7 +535,7 @@ mod tests {
|
||||||
t!(b"foo/\xFFbar", filename_display, "\u{FFFD}bar");
|
t!(b"foo/\xFFbar", filename_display, "\u{FFFD}bar");
|
||||||
t!(b"/", filename_display, "");
|
t!(b"/", filename_display, "");
|
||||||
|
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
($path:expr, $exp:expr) => (
|
($path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -550,7 +550,7 @@ mod tests {
|
||||||
assert!(mo.as_slice() == $exp);
|
assert!(mo.as_slice() == $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!("foo", "foo");
|
t!("foo", "foo");
|
||||||
t!(b"foo\x80", "foo\u{FFFD}");
|
t!(b"foo\x80", "foo\u{FFFD}");
|
||||||
|
@ -562,7 +562,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
($path:expr, $exp:expr, $expf:expr) => (
|
($path:expr, $exp:expr, $expf:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -572,7 +572,7 @@ mod tests {
|
||||||
assert!(f == $expf);
|
assert!(f == $expf);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(b"foo", "foo", "foo");
|
t!(b"foo", "foo", "foo");
|
||||||
t!(b"foo/bar", "foo/bar", "bar");
|
t!(b"foo/bar", "foo/bar", "bar");
|
||||||
|
@ -585,7 +585,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_components() {
|
fn test_components() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $op:ident, $exp:expr) => (
|
(s: $path:expr, $op:ident, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -606,7 +606,7 @@ mod tests {
|
||||||
assert!(path.$op() == $exp);
|
assert!(path.$op() == $exp);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(v: b"a/b/c", filename, Some(b"c"));
|
t!(v: b"a/b/c", filename, Some(b"c"));
|
||||||
t!(v: b"a/b/c\xFF", filename, Some(b"c\xFF"));
|
t!(v: b"a/b/c\xFF", filename, Some(b"c\xFF"));
|
||||||
|
@ -669,7 +669,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push() {
|
fn test_push() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $join:expr) => (
|
(s: $path:expr, $join:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -680,7 +680,7 @@ mod tests {
|
||||||
assert!(p1 == p2.join(join));
|
assert!(p1 == p2.join(join));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", "..");
|
t!(s: "a/b/c", "..");
|
||||||
t!(s: "/a/b/c", "d");
|
t!(s: "/a/b/c", "d");
|
||||||
|
@ -690,7 +690,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_path() {
|
fn test_push_path() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let mut p = Path::new($path);
|
let mut p = Path::new($path);
|
||||||
|
@ -699,7 +699,7 @@ mod tests {
|
||||||
assert!(p.as_str() == Some($exp));
|
assert!(p.as_str() == Some($exp));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", "d", "a/b/c/d");
|
t!(s: "a/b/c", "d", "a/b/c/d");
|
||||||
t!(s: "/a/b/c", "d", "/a/b/c/d");
|
t!(s: "/a/b/c", "d", "/a/b/c/d");
|
||||||
|
@ -711,7 +711,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_many() {
|
fn test_push_many() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let mut p = Path::new($path);
|
let mut p = Path::new($path);
|
||||||
|
@ -726,7 +726,7 @@ mod tests {
|
||||||
assert!(p.as_vec() == $exp);
|
assert!(p.as_vec() == $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
|
t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
|
||||||
t!(s: "a/b/c", ["d", "/e"], "/e");
|
t!(s: "a/b/c", ["d", "/e"], "/e");
|
||||||
|
@ -739,7 +739,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pop() {
|
fn test_pop() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $left:expr, $right:expr) => (
|
(s: $path:expr, $left:expr, $right:expr) => (
|
||||||
{
|
{
|
||||||
let mut p = Path::new($path);
|
let mut p = Path::new($path);
|
||||||
|
@ -756,7 +756,7 @@ mod tests {
|
||||||
assert!(result == $right);
|
assert!(result == $right);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(b: b"a/b/c", b"a/b", true);
|
t!(b: b"a/b/c", b"a/b", true);
|
||||||
t!(b: b"a", b".", true);
|
t!(b: b"a", b".", true);
|
||||||
|
@ -795,7 +795,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_join_path() {
|
fn test_join_path() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -804,7 +804,7 @@ mod tests {
|
||||||
assert!(res.as_str() == Some($exp));
|
assert!(res.as_str() == Some($exp));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", "..", "a/b");
|
t!(s: "a/b/c", "..", "a/b");
|
||||||
t!(s: "/a/b/c", "d", "/a/b/c/d");
|
t!(s: "/a/b/c", "d", "/a/b/c/d");
|
||||||
|
@ -816,7 +816,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_join_many() {
|
fn test_join_many() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -831,7 +831,7 @@ mod tests {
|
||||||
assert!(res.as_vec() == $exp);
|
assert!(res.as_vec() == $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
|
t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
|
||||||
t!(s: "a/b/c", ["..", "d"], "a/b/d");
|
t!(s: "a/b/c", ["..", "d"], "a/b/d");
|
||||||
|
@ -894,7 +894,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_setters() {
|
fn test_setters() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
|
(s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -915,7 +915,7 @@ mod tests {
|
||||||
assert!(p1 == p2.$with(arg));
|
assert!(p1 == p2.$with(arg));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(v: b"a/b/c", set_filename, with_filename, b"d");
|
t!(v: b"a/b/c", set_filename, with_filename, b"d");
|
||||||
t!(v: b"/", set_filename, with_filename, b"foo");
|
t!(v: b"/", set_filename, with_filename, b"foo");
|
||||||
|
@ -938,7 +938,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_getters() {
|
fn test_getters() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -969,7 +969,7 @@ mod tests {
|
||||||
assert!(path.extension() == $ext);
|
assert!(path.extension() == $ext);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None);
|
t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None);
|
||||||
t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None);
|
t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None);
|
||||||
|
@ -1008,7 +1008,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_absolute() {
|
fn test_is_absolute() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $abs:expr, $rel:expr) => (
|
(s: $path:expr, $abs:expr, $rel:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1016,7 +1016,7 @@ mod tests {
|
||||||
assert_eq!(path.is_relative(), $rel);
|
assert_eq!(path.is_relative(), $rel);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
t!(s: "a/b/c", false, true);
|
t!(s: "a/b/c", false, true);
|
||||||
t!(s: "/a/b/c", true, false);
|
t!(s: "/a/b/c", true, false);
|
||||||
t!(s: "a", false, true);
|
t!(s: "a", false, true);
|
||||||
|
@ -1029,7 +1029,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_ancestor_of() {
|
fn test_is_ancestor_of() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $dest:expr, $exp:expr) => (
|
(s: $path:expr, $dest:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1037,7 +1037,7 @@ mod tests {
|
||||||
assert_eq!(path.is_ancestor_of(&dest), $exp);
|
assert_eq!(path.is_ancestor_of(&dest), $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", "a/b/c/d", true);
|
t!(s: "a/b/c", "a/b/c/d", true);
|
||||||
t!(s: "a/b/c", "a/b/c", true);
|
t!(s: "a/b/c", "a/b/c", true);
|
||||||
|
@ -1063,7 +1063,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ends_with_path() {
|
fn test_ends_with_path() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $child:expr, $exp:expr) => (
|
(s: $path:expr, $child:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1078,7 +1078,7 @@ mod tests {
|
||||||
assert_eq!(path.ends_with_path(&child), $exp);
|
assert_eq!(path.ends_with_path(&child), $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", "c", true);
|
t!(s: "a/b/c", "c", true);
|
||||||
t!(s: "a/b/c", "d", false);
|
t!(s: "a/b/c", "d", false);
|
||||||
|
@ -1102,7 +1102,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_path_relative_from() {
|
fn test_path_relative_from() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $other:expr, $exp:expr) => (
|
(s: $path:expr, $other:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1111,7 +1111,7 @@ mod tests {
|
||||||
assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
|
assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a/b/c", "a/b", Some("c"));
|
t!(s: "a/b/c", "a/b", Some("c"));
|
||||||
t!(s: "a/b/c", "a/b/d", Some("../c"));
|
t!(s: "a/b/c", "a/b/d", Some("../c"));
|
||||||
|
@ -1147,7 +1147,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_components_iter() {
|
fn test_components_iter() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $exp:expr) => (
|
(s: $path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1173,7 +1173,7 @@ mod tests {
|
||||||
assert_eq!(comps, exp)
|
assert_eq!(comps, exp)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(b: b"a/b/c", [b"a", b"b", b"c"]);
|
t!(b: b"a/b/c", [b"a", b"b", b"c"]);
|
||||||
t!(b: b"/\xFF/a/\x80", [b"\xFF", b"a", b"\x80"]);
|
t!(b: b"/\xFF/a/\x80", [b"\xFF", b"a", b"\x80"]);
|
||||||
|
@ -1193,7 +1193,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_str_components() {
|
fn test_str_components() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(b: $arg:expr, $exp:expr) => (
|
(b: $arg:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($arg);
|
let path = Path::new($arg);
|
||||||
|
@ -1205,7 +1205,7 @@ mod tests {
|
||||||
assert_eq!(comps, exp);
|
assert_eq!(comps, exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(b: b"a/b/c", [Some("a"), Some("b"), Some("c")]);
|
t!(b: b"a/b/c", [Some("a"), Some("b"), Some("c")]);
|
||||||
t!(b: b"/\xFF/a/\x80", [None, Some("a"), None]);
|
t!(b: b"/\xFF/a/\x80", [None, Some("a"), None]);
|
||||||
|
|
|
@ -1127,7 +1127,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_prefix() {
|
fn test_parse_prefix() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
($path:expr, $exp:expr) => (
|
($path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -1137,7 +1137,7 @@ mod tests {
|
||||||
"parse_prefix(\"{}\"): expected {}, found {}", path, exp, res);
|
"parse_prefix(\"{}\"): expected {}, found {}", path, exp, res);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5)));
|
t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5)));
|
||||||
t!("\\\\", None);
|
t!("\\\\", None);
|
||||||
|
@ -1326,7 +1326,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
($path:expr, $exp:expr, $expf:expr) => (
|
($path:expr, $exp:expr, $expf:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1336,7 +1336,7 @@ mod tests {
|
||||||
assert_eq!(f, $expf);
|
assert_eq!(f, $expf);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!("foo", "foo", "foo");
|
t!("foo", "foo", "foo");
|
||||||
t!("foo\\bar", "foo\\bar", "bar");
|
t!("foo\\bar", "foo\\bar", "bar");
|
||||||
|
@ -1345,7 +1345,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_components() {
|
fn test_components() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $op:ident, $exp:expr) => (
|
(s: $path:expr, $op:ident, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -1368,7 +1368,7 @@ mod tests {
|
||||||
assert!(path.$op() == $exp);
|
assert!(path.$op() == $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(v: b"a\\b\\c", filename, Some(b"c"));
|
t!(v: b"a\\b\\c", filename, Some(b"c"));
|
||||||
t!(s: "a\\b\\c", filename_str, "c");
|
t!(s: "a\\b\\c", filename_str, "c");
|
||||||
|
@ -1468,7 +1468,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push() {
|
fn test_push() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $join:expr) => (
|
(s: $path:expr, $join:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -1479,7 +1479,7 @@ mod tests {
|
||||||
assert!(p1 == p2.join(join));
|
assert!(p1 == p2.join(join));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "..");
|
t!(s: "a\\b\\c", "..");
|
||||||
t!(s: "\\a\\b\\c", "d");
|
t!(s: "\\a\\b\\c", "d");
|
||||||
|
@ -1503,7 +1503,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_path() {
|
fn test_push_path() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let mut p = Path::new($path);
|
let mut p = Path::new($path);
|
||||||
|
@ -1512,7 +1512,7 @@ mod tests {
|
||||||
assert_eq!(p.as_str(), Some($exp));
|
assert_eq!(p.as_str(), Some($exp));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "d", "a\\b\\c\\d");
|
t!(s: "a\\b\\c", "d", "a\\b\\c\\d");
|
||||||
t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
|
t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
|
||||||
|
@ -1555,7 +1555,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_many() {
|
fn test_push_many() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let mut p = Path::new($path);
|
let mut p = Path::new($path);
|
||||||
|
@ -1570,7 +1570,7 @@ mod tests {
|
||||||
assert_eq!(p.as_vec(), $exp);
|
assert_eq!(p.as_vec(), $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
|
t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
|
||||||
t!(s: "a\\b\\c", ["d", "\\e"], "\\e");
|
t!(s: "a\\b\\c", ["d", "\\e"], "\\e");
|
||||||
|
@ -1584,7 +1584,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pop() {
|
fn test_pop() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $left:expr, $right:expr) => (
|
(s: $path:expr, $left:expr, $right:expr) => (
|
||||||
{
|
{
|
||||||
let pstr = $path;
|
let pstr = $path;
|
||||||
|
@ -1605,7 +1605,7 @@ mod tests {
|
||||||
assert!(result == $right);
|
assert!(result == $right);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "a\\b", true);
|
t!(s: "a\\b\\c", "a\\b", true);
|
||||||
t!(s: "a", ".", true);
|
t!(s: "a", ".", true);
|
||||||
|
@ -1673,7 +1673,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_join_path() {
|
fn test_join_path() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1682,7 +1682,7 @@ mod tests {
|
||||||
assert_eq!(res.as_str(), Some($exp));
|
assert_eq!(res.as_str(), Some($exp));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "..", "a\\b");
|
t!(s: "a\\b\\c", "..", "a\\b");
|
||||||
t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
|
t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
|
||||||
|
@ -1696,7 +1696,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_join_many() {
|
fn test_join_many() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1711,7 +1711,7 @@ mod tests {
|
||||||
assert_eq!(res.as_vec(), $exp);
|
assert_eq!(res.as_vec(), $exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
|
t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
|
||||||
t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d");
|
t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d");
|
||||||
|
@ -1724,7 +1724,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_helpers() {
|
fn test_with_helpers() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $op:ident, $arg:expr, $res:expr) => (
|
(s: $path:expr, $op:ident, $arg:expr, $res:expr) => (
|
||||||
{
|
{
|
||||||
let pstr = $path;
|
let pstr = $path;
|
||||||
|
@ -1737,7 +1737,7 @@ mod tests {
|
||||||
pstr, stringify!($op), arg, exp, res.as_str().unwrap());
|
pstr, stringify!($op), arg, exp, res.as_str().unwrap());
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d");
|
t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d");
|
||||||
t!(s: ".", with_filename, "foo", "foo");
|
t!(s: ".", with_filename, "foo", "foo");
|
||||||
|
@ -1809,7 +1809,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_setters() {
|
fn test_setters() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
|
(s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -1830,7 +1830,7 @@ mod tests {
|
||||||
assert!(p1 == p2.$with(arg));
|
assert!(p1 == p2.$with(arg));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(v: b"a\\b\\c", set_filename, with_filename, b"d");
|
t!(v: b"a\\b\\c", set_filename, with_filename, b"d");
|
||||||
t!(v: b"\\", set_filename, with_filename, b"foo");
|
t!(v: b"\\", set_filename, with_filename, b"foo");
|
||||||
|
@ -1854,7 +1854,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_getters() {
|
fn test_getters() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||||
{
|
{
|
||||||
let path = $path;
|
let path = $path;
|
||||||
|
@ -1885,7 +1885,7 @@ mod tests {
|
||||||
assert!(path.extension() == $ext);
|
assert!(path.extension() == $ext);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None);
|
t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None);
|
||||||
t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None);
|
t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None);
|
||||||
|
@ -1920,7 +1920,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_absolute() {
|
fn test_is_absolute() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => (
|
($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1939,7 +1939,7 @@ mod tests {
|
||||||
path.as_str().unwrap(), rel, b);
|
path.as_str().unwrap(), rel, b);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
t!("a\\b\\c", false, false, false, true);
|
t!("a\\b\\c", false, false, false, true);
|
||||||
t!("\\a\\b\\c", false, true, false, false);
|
t!("\\a\\b\\c", false, true, false, false);
|
||||||
t!("a", false, false, false, true);
|
t!("a", false, false, false, true);
|
||||||
|
@ -1960,7 +1960,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_ancestor_of() {
|
fn test_is_ancestor_of() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $dest:expr, $exp:expr) => (
|
(s: $path:expr, $dest:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -1972,7 +1972,7 @@ mod tests {
|
||||||
path.as_str().unwrap(), dest.as_str().unwrap(), exp, res);
|
path.as_str().unwrap(), dest.as_str().unwrap(), exp, res);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "a\\b\\c\\d", true);
|
t!(s: "a\\b\\c", "a\\b\\c\\d", true);
|
||||||
t!(s: "a\\b\\c", "a\\b\\c", true);
|
t!(s: "a\\b\\c", "a\\b\\c", true);
|
||||||
|
@ -2063,7 +2063,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ends_with_path() {
|
fn test_ends_with_path() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $child:expr, $exp:expr) => (
|
(s: $path:expr, $child:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -2071,7 +2071,7 @@ mod tests {
|
||||||
assert_eq!(path.ends_with_path(&child), $exp);
|
assert_eq!(path.ends_with_path(&child), $exp);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "c", true);
|
t!(s: "a\\b\\c", "c", true);
|
||||||
t!(s: "a\\b\\c", "d", false);
|
t!(s: "a\\b\\c", "d", false);
|
||||||
|
@ -2095,7 +2095,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_path_relative_from() {
|
fn test_path_relative_from() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $other:expr, $exp:expr) => (
|
(s: $path:expr, $other:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -2108,7 +2108,7 @@ mod tests {
|
||||||
res.as_ref().and_then(|x| x.as_str()));
|
res.as_ref().and_then(|x| x.as_str()));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", "a\\b", Some("c"));
|
t!(s: "a\\b\\c", "a\\b", Some("c"));
|
||||||
t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c"));
|
t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c"));
|
||||||
|
@ -2229,7 +2229,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_str_components() {
|
fn test_str_components() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $exp:expr) => (
|
(s: $path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -2243,7 +2243,7 @@ mod tests {
|
||||||
assert_eq!(comps, exp);
|
assert_eq!(comps, exp);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: b"a\\b\\c", ["a", "b", "c"]);
|
t!(s: b"a\\b\\c", ["a", "b", "c"]);
|
||||||
t!(s: "a\\b\\c", ["a", "b", "c"]);
|
t!(s: "a\\b\\c", ["a", "b", "c"]);
|
||||||
|
@ -2287,7 +2287,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_components_iter() {
|
fn test_components_iter() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
(s: $path:expr, $exp:expr) => (
|
(s: $path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -2299,7 +2299,7 @@ mod tests {
|
||||||
assert_eq!(comps, exp);
|
assert_eq!(comps, exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(s: "a\\b\\c", [b"a", b"b", b"c"]);
|
t!(s: "a\\b\\c", [b"a", b"b", b"c"]);
|
||||||
t!(s: ".", [b"."]);
|
t!(s: ".", [b"."]);
|
||||||
|
@ -2308,7 +2308,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_make_non_verbatim() {
|
fn test_make_non_verbatim() {
|
||||||
macro_rules! t(
|
macro_rules! t {
|
||||||
($path:expr, $exp:expr) => (
|
($path:expr, $exp:expr) => (
|
||||||
{
|
{
|
||||||
let path = Path::new($path);
|
let path = Path::new($path);
|
||||||
|
@ -2317,7 +2317,7 @@ mod tests {
|
||||||
assert!(make_non_verbatim(&path) == exp);
|
assert!(make_non_verbatim(&path) == exp);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
}
|
||||||
|
|
||||||
t!(r"\a\b\c", Some(r"\a\b\c"));
|
t!(r"\a\b\c", Some(r"\a\b\c"));
|
||||||
t!(r"a\b\c", Some(r"a\b\c"));
|
t!(r"a\b\c", Some(r"a\b\c"));
|
||||||
|
|
|
@ -23,11 +23,14 @@ mod imp {
|
||||||
use path::Path;
|
use path::Path;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::reader::ReaderRng;
|
use rand::reader::ReaderRng;
|
||||||
use result::Result::{Ok, Err};
|
use result::Result::Ok;
|
||||||
use slice::SliceExt;
|
use slice::SliceExt;
|
||||||
use mem;
|
use mem;
|
||||||
use os::errno;
|
use os::errno;
|
||||||
|
|
||||||
|
// NOTE: for old macros; remove after the next snapshot
|
||||||
|
#[cfg(stage0)] use result::Result::Err;
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux",
|
#[cfg(all(target_os = "linux",
|
||||||
any(target_arch = "x86_64",
|
any(target_arch = "x86_64",
|
||||||
target_arch = "x86",
|
target_arch = "x86",
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
//! These macros call functions which are only accessible in the `rt` module, so
|
//! These macros call functions which are only accessible in the `rt` module, so
|
||||||
//! they aren't defined anywhere outside of the `rt` module.
|
//! they aren't defined anywhere outside of the `rt` module.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
macro_rules! rterrln {
|
macro_rules! rterrln {
|
||||||
($fmt:expr $($arg:tt)*) => ( {
|
($fmt:expr $($arg:tt)*) => ( {
|
||||||
::rt::util::dumb_print(format_args!(concat!($fmt, "\n") $($arg)*))
|
::rt::util::dumb_print(format_args!(concat!($fmt, "\n") $($arg)*))
|
||||||
|
|
|
@ -39,6 +39,8 @@ pub use alloc::heap;
|
||||||
pub mod backtrace;
|
pub mod backtrace;
|
||||||
|
|
||||||
// Internals
|
// Internals
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
// These should be refactored/moved/made private over time
|
// These should be refactored/moved/made private over time
|
||||||
|
|
|
@ -34,13 +34,14 @@
|
||||||
//! will want to make use of some form of **interior mutability** through the
|
//! will want to make use of some form of **interior mutability** through the
|
||||||
//! `Cell` or `RefCell` types.
|
//! `Cell` or `RefCell` types.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
#![stable]
|
#![stable]
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
|
|
||||||
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
pub mod scoped;
|
pub mod scoped;
|
||||||
|
|
||||||
// Sure wish we had macro hygiene, no?
|
// Sure wish we had macro hygiene, no?
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
//! });
|
//! });
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
#![unstable = "scoped TLS has yet to have wide enough use to fully consider \
|
#![unstable = "scoped TLS has yet to have wide enough use to fully consider \
|
||||||
stabilizing its interface"]
|
stabilizing its interface"]
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,10 @@ use ops::{Add, Sub, Mul, Div, Neg, FnOnce};
|
||||||
use option::Option;
|
use option::Option;
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
use num::Int;
|
use num::Int;
|
||||||
use result::Result;
|
use result::Result::Ok;
|
||||||
use result::Result::{Ok, Err};
|
|
||||||
|
// NOTE: for old macros; remove after the next snapshot
|
||||||
|
#[cfg(stage0)] use result::Result::Err;
|
||||||
|
|
||||||
/// The number of nanoseconds in a microsecond.
|
/// The number of nanoseconds in a microsecond.
|
||||||
const NANOS_PER_MICRO: i32 = 1000;
|
const NANOS_PER_MICRO: i32 = 1000;
|
||||||
|
|
|
@ -476,7 +476,7 @@ pub struct Crate {
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub config: CrateConfig,
|
pub config: CrateConfig,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub exported_macros: Vec<P<Item>>
|
pub exported_macros: Vec<MacroDef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MetaItem = Spanned<MetaItem_>;
|
pub type MetaItem = Spanned<MetaItem_>;
|
||||||
|
@ -884,6 +884,7 @@ impl TokenTree {
|
||||||
match *self {
|
match *self {
|
||||||
TtToken(_, token::DocComment(_)) => 2,
|
TtToken(_, token::DocComment(_)) => 2,
|
||||||
TtToken(_, token::SubstNt(..)) => 2,
|
TtToken(_, token::SubstNt(..)) => 2,
|
||||||
|
TtToken(_, token::SpecialVarNt(..)) => 2,
|
||||||
TtToken(_, token::MatchNt(..)) => 3,
|
TtToken(_, token::MatchNt(..)) => 3,
|
||||||
TtDelimited(_, ref delimed) => {
|
TtDelimited(_, ref delimed) => {
|
||||||
delimed.tts.len() + 2
|
delimed.tts.len() + 2
|
||||||
|
@ -925,6 +926,12 @@ impl TokenTree {
|
||||||
TtToken(sp, token::Ident(name, name_st))];
|
TtToken(sp, token::Ident(name, name_st))];
|
||||||
v[index]
|
v[index]
|
||||||
}
|
}
|
||||||
|
(&TtToken(sp, token::SpecialVarNt(var)), _) => {
|
||||||
|
let v = [TtToken(sp, token::Dollar),
|
||||||
|
TtToken(sp, token::Ident(token::str_to_ident(var.as_str()),
|
||||||
|
token::Plain))];
|
||||||
|
v[index]
|
||||||
|
}
|
||||||
(&TtToken(sp, token::MatchNt(name, kind, name_st, kind_st)), _) => {
|
(&TtToken(sp, token::MatchNt(name, kind, name_st, kind_st)), _) => {
|
||||||
let v = [TtToken(sp, token::SubstNt(name, name_st)),
|
let v = [TtToken(sp, token::SubstNt(name, name_st)),
|
||||||
TtToken(sp, token::Colon),
|
TtToken(sp, token::Colon),
|
||||||
|
@ -1689,6 +1696,21 @@ pub enum InlinedItem {
|
||||||
IIForeign(P<ForeignItem>),
|
IIForeign(P<ForeignItem>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A macro definition, in this crate or imported from another.
|
||||||
|
///
|
||||||
|
/// Not parsed directly, but created on macro import or `macro_rules!` expansion.
|
||||||
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
|
||||||
|
pub struct MacroDef {
|
||||||
|
pub ident: Ident,
|
||||||
|
pub attrs: Vec<Attribute>,
|
||||||
|
pub id: NodeId,
|
||||||
|
pub span: Span,
|
||||||
|
pub imported_from: Option<Ident>,
|
||||||
|
pub export: bool,
|
||||||
|
pub use_locally: bool,
|
||||||
|
pub body: Vec<TokenTree>,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use serialize::json;
|
use serialize::json;
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_diagnostic {
|
macro_rules! register_diagnostic {
|
||||||
($code:tt, $description:tt) => (__register_diagnostic! { $code, $description });
|
($code:tt, $description:tt) => (__register_diagnostic! { $code, $description });
|
||||||
|
|
|
@ -16,6 +16,7 @@ use codemap;
|
||||||
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
|
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
|
||||||
use ext;
|
use ext;
|
||||||
use ext::expand;
|
use ext::expand;
|
||||||
|
use ext::tt::macro_rules;
|
||||||
use parse;
|
use parse;
|
||||||
use parse::parser;
|
use parse::parser;
|
||||||
use parse::token;
|
use parse::token;
|
||||||
|
@ -28,19 +29,6 @@ use fold::Folder;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
// new-style macro! tt code:
|
|
||||||
//
|
|
||||||
// MacResult, NormalTT, IdentTT
|
|
||||||
//
|
|
||||||
// also note that ast::Mac used to have a bunch of extraneous cases and
|
|
||||||
// is now probably a redundant AST node, can be merged with
|
|
||||||
// ast::MacInvocTT.
|
|
||||||
|
|
||||||
pub struct MacroDef {
|
|
||||||
pub name: String,
|
|
||||||
pub ext: SyntaxExtension
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ItemDecorator {
|
pub trait ItemDecorator {
|
||||||
fn expand(&self,
|
fn expand(&self,
|
||||||
ecx: &mut ExtCtxt,
|
ecx: &mut ExtCtxt,
|
||||||
|
@ -140,13 +128,6 @@ impl<F> IdentMacroExpander for F
|
||||||
/// methods are spliced into the AST at the callsite of the macro (or
|
/// methods are spliced into the AST at the callsite of the macro (or
|
||||||
/// just into the compiler's internal macro table, for `make_def`).
|
/// just into the compiler's internal macro table, for `make_def`).
|
||||||
pub trait MacResult {
|
pub trait MacResult {
|
||||||
/// Attempt to define a new macro.
|
|
||||||
// this should go away; the idea that a macro might expand into
|
|
||||||
// either a macro definition or an expression, depending on what
|
|
||||||
// the context wants, is kind of silly.
|
|
||||||
fn make_def(&mut self) -> Option<MacroDef> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
/// Create an expression.
|
/// Create an expression.
|
||||||
fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
|
fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
|
||||||
None
|
None
|
||||||
|
@ -328,13 +309,8 @@ pub enum SyntaxExtension {
|
||||||
///
|
///
|
||||||
IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
||||||
|
|
||||||
/// An ident macro that has two properties:
|
/// Represents `macro_rules!` itself.
|
||||||
/// - it adds a macro definition to the environment, and
|
MacroRulesTT,
|
||||||
/// - the definition it adds doesn't introduce any new
|
|
||||||
/// identifiers.
|
|
||||||
///
|
|
||||||
/// `macro_rules!` is a LetSyntaxTT
|
|
||||||
LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||||
|
@ -364,8 +340,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut syntax_expanders = SyntaxEnv::new();
|
let mut syntax_expanders = SyntaxEnv::new();
|
||||||
syntax_expanders.insert(intern("macro_rules"),
|
syntax_expanders.insert(intern("macro_rules"), MacroRulesTT);
|
||||||
LetSyntaxTT(box ext::tt::macro_rules::add_new_extension, None));
|
|
||||||
syntax_expanders.insert(intern("fmt"),
|
syntax_expanders.insert(intern("fmt"),
|
||||||
builtin_normal_expander(
|
builtin_normal_expander(
|
||||||
ext::fmt::expand_syntax_ext));
|
ext::fmt::expand_syntax_ext));
|
||||||
|
@ -475,7 +450,7 @@ pub struct ExtCtxt<'a> {
|
||||||
|
|
||||||
pub mod_path: Vec<ast::Ident> ,
|
pub mod_path: Vec<ast::Ident> ,
|
||||||
pub trace_mac: bool,
|
pub trace_mac: bool,
|
||||||
pub exported_macros: Vec<P<ast::Item>>,
|
pub exported_macros: Vec<ast::MacroDef>,
|
||||||
|
|
||||||
pub syntax_env: SyntaxEnv,
|
pub syntax_env: SyntaxEnv,
|
||||||
pub recursion_count: uint,
|
pub recursion_count: uint,
|
||||||
|
@ -594,6 +569,17 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_macro(&mut self, def: ast::MacroDef) {
|
||||||
|
if def.export {
|
||||||
|
self.exported_macros.push(def.clone());
|
||||||
|
}
|
||||||
|
if def.use_locally {
|
||||||
|
let ext = macro_rules::compile(self, &def);
|
||||||
|
self.syntax_env.insert(def.ident.name, ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Emit `msg` attached to `sp`, and stop compilation immediately.
|
/// Emit `msg` attached to `sp`, and stop compilation immediately.
|
||||||
///
|
///
|
||||||
/// `span_err` should be strongly preferred where-ever possible:
|
/// `span_err` should be strongly preferred where-ever possible:
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub fn expand_deriving_eq<F>(cx: &mut ExtCtxt,
|
||||||
cx, span, substr)
|
cx, span, substr)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! md (
|
macro_rules! md {
|
||||||
($name:expr, $f:ident) => { {
|
($name:expr, $f:ident) => { {
|
||||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||||
let attrs = vec!(cx.attribute(span, inline));
|
let attrs = vec!(cx.attribute(span, inline));
|
||||||
|
@ -77,7 +77,7 @@ pub fn expand_deriving_eq<F>(cx: &mut ExtCtxt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
);
|
}
|
||||||
|
|
||||||
let trait_def = TraitDef {
|
let trait_def = TraitDef {
|
||||||
span: span,
|
span: span,
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub fn expand_deriving_ord<F>(cx: &mut ExtCtxt,
|
||||||
push: F) where
|
push: F) where
|
||||||
F: FnOnce(P<Item>),
|
F: FnOnce(P<Item>),
|
||||||
{
|
{
|
||||||
macro_rules! md (
|
macro_rules! md {
|
||||||
($name:expr, $op:expr, $equal:expr) => { {
|
($name:expr, $op:expr, $equal:expr) => { {
|
||||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||||
let attrs = vec!(cx.attribute(span, inline));
|
let attrs = vec!(cx.attribute(span, inline));
|
||||||
|
@ -43,7 +43,7 @@ pub fn expand_deriving_ord<F>(cx: &mut ExtCtxt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
);
|
}
|
||||||
|
|
||||||
let ordering_ty = Literal(Path::new(vec!["std", "cmp", "Ordering"]));
|
let ordering_ty = Literal(Path::new(vec!["std", "cmp", "Ordering"]));
|
||||||
let ret_ty = Literal(Path::new_(vec!["std", "option", "Option"],
|
let ret_ty = Literal(Path::new_(vec!["std", "option", "Option"],
|
||||||
|
|
|
@ -71,9 +71,11 @@ pub fn expand_meta_derive(cx: &mut ExtCtxt,
|
||||||
MetaNameValue(ref tname, _) |
|
MetaNameValue(ref tname, _) |
|
||||||
MetaList(ref tname, _) |
|
MetaList(ref tname, _) |
|
||||||
MetaWord(ref tname) => {
|
MetaWord(ref tname) => {
|
||||||
macro_rules! expand(($func:path) => ($func(cx, titem.span,
|
macro_rules! expand {
|
||||||
&**titem, item,
|
($func:path) => ($func(cx, titem.span, &**titem, item,
|
||||||
|i| push.call_mut((i,)))));
|
|i| push.call_mut((i,))))
|
||||||
|
}
|
||||||
|
|
||||||
match tname.get() {
|
match tname.get() {
|
||||||
"Clone" => expand!(clone::expand_deriving_clone),
|
"Clone" => expand!(clone::expand_deriving_clone),
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
use self::Either::*;
|
|
||||||
|
|
||||||
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
||||||
use ast::{Local, Ident, MacInvocTT};
|
use ast::{Local, Ident, MacInvocTT};
|
||||||
|
@ -33,11 +32,6 @@ use util::small_vector::SmallVector;
|
||||||
use visit;
|
use visit;
|
||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
|
|
||||||
enum Either<L,R> {
|
|
||||||
Left(L),
|
|
||||||
Right(R)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expand_type(t: P<ast::Ty>,
|
pub fn expand_type(t: P<ast::Ty>,
|
||||||
fld: &mut MacroExpander,
|
fld: &mut MacroExpander,
|
||||||
impl_ty: Option<P<ast::Ty>>)
|
impl_ty: Option<P<ast::Ty>>)
|
||||||
|
@ -445,9 +439,9 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
if valid_ident {
|
if valid_ident {
|
||||||
fld.cx.mod_push(it.ident);
|
fld.cx.mod_push(it.ident);
|
||||||
}
|
}
|
||||||
let macro_escape = contains_macro_escape(new_attrs[]);
|
let macro_use = contains_macro_use(fld, new_attrs[]);
|
||||||
let result = with_exts_frame!(fld.cx.syntax_env,
|
let result = with_exts_frame!(fld.cx.syntax_env,
|
||||||
macro_escape,
|
macro_use,
|
||||||
noop_fold_item(it, fld));
|
noop_fold_item(it, fld));
|
||||||
if valid_ident {
|
if valid_ident {
|
||||||
fld.cx.mod_pop();
|
fld.cx.mod_pop();
|
||||||
|
@ -527,15 +521,34 @@ fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Ite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// does this attribute list contain "macro_escape" ?
|
// does this attribute list contain "macro_use" ?
|
||||||
fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
|
fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
|
||||||
attr::contains_name(attrs, "macro_escape")
|
for attr in attrs.iter() {
|
||||||
|
let mut is_use = attr.check_name("macro_use");
|
||||||
|
if attr.check_name("macro_escape") {
|
||||||
|
fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
|
||||||
|
is_use = true;
|
||||||
|
if let ast::AttrInner = attr.node.style {
|
||||||
|
fld.cx.span_help(attr.span, "consider an outer attribute, \
|
||||||
|
#[macro_use] mod ...");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_use {
|
||||||
|
match attr.node.value.node {
|
||||||
|
ast::MetaWord(..) => (),
|
||||||
|
_ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"),
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support for item-position macro invocations, exactly the same
|
// Support for item-position macro invocations, exactly the same
|
||||||
// logic as for expression-position macro invocations.
|
// logic as for expression-position macro invocations.
|
||||||
pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
pub fn expand_item_mac(it: P<ast::Item>,
|
||||||
-> SmallVector<P<ast::Item>> {
|
fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
|
||||||
let (extname, path_span, tts) = match it.node {
|
let (extname, path_span, tts) = match it.node {
|
||||||
ItemMac(codemap::Spanned {
|
ItemMac(codemap::Spanned {
|
||||||
node: MacInvocTT(ref pth, ref tts, _),
|
node: MacInvocTT(ref pth, ref tts, _),
|
||||||
|
@ -548,8 +561,8 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
|
|
||||||
let extnamestr = token::get_ident(extname);
|
let extnamestr = token::get_ident(extname);
|
||||||
let fm = fresh_mark();
|
let fm = fresh_mark();
|
||||||
let def_or_items = {
|
let items = {
|
||||||
let mut expanded = match fld.cx.syntax_env.find(&extname.name) {
|
let expanded = match fld.cx.syntax_env.find(&extname.name) {
|
||||||
None => {
|
None => {
|
||||||
fld.cx.span_err(path_span,
|
fld.cx.span_err(path_span,
|
||||||
format!("macro undefined: '{}!'",
|
format!("macro undefined: '{}!'",
|
||||||
|
@ -600,11 +613,10 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
let marked_tts = mark_tts(tts[], fm);
|
let marked_tts = mark_tts(tts[], fm);
|
||||||
expander.expand(fld.cx, it.span, it.ident, marked_tts)
|
expander.expand(fld.cx, it.span, it.ident, marked_tts)
|
||||||
}
|
}
|
||||||
LetSyntaxTT(ref expander, span) => {
|
MacroRulesTT => {
|
||||||
if it.ident.name == parse::token::special_idents::invalid.name {
|
if it.ident.name == parse::token::special_idents::invalid.name {
|
||||||
fld.cx.span_err(path_span,
|
fld.cx.span_err(path_span,
|
||||||
format!("macro {}! expects an ident argument",
|
format!("macro_rules! expects an ident argument")[]);
|
||||||
extnamestr.get())[]);
|
|
||||||
return SmallVector::zero();
|
return SmallVector::zero();
|
||||||
}
|
}
|
||||||
fld.cx.bt_push(ExpnInfo {
|
fld.cx.bt_push(ExpnInfo {
|
||||||
|
@ -612,11 +624,26 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
callee: NameAndSpan {
|
callee: NameAndSpan {
|
||||||
name: extnamestr.get().to_string(),
|
name: extnamestr.get().to_string(),
|
||||||
format: MacroBang,
|
format: MacroBang,
|
||||||
span: span
|
span: None,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// DON'T mark before expansion:
|
// DON'T mark before expansion.
|
||||||
expander.expand(fld.cx, it.span, it.ident, tts)
|
|
||||||
|
let def = ast::MacroDef {
|
||||||
|
ident: it.ident,
|
||||||
|
attrs: it.attrs.clone(),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
span: it.span,
|
||||||
|
imported_from: None,
|
||||||
|
export: attr::contains_name(it.attrs.as_slice(), "macro_export"),
|
||||||
|
use_locally: true,
|
||||||
|
body: tts,
|
||||||
|
};
|
||||||
|
fld.cx.insert_macro(def);
|
||||||
|
|
||||||
|
// macro_rules! has a side effect but expands to nothing.
|
||||||
|
fld.cx.bt_pop();
|
||||||
|
return SmallVector::zero();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
fld.cx.span_err(it.span,
|
fld.cx.span_err(it.span,
|
||||||
|
@ -627,31 +654,17 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match expanded.make_def() {
|
expanded.make_items()
|
||||||
Some(def) => Left(def),
|
|
||||||
None => Right(expanded.make_items())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let items = match def_or_items {
|
let items = match items {
|
||||||
Left(MacroDef { name, ext }) => {
|
Some(items) => {
|
||||||
// hidden invariant: this should only be possible as the
|
|
||||||
// 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.cx.syntax_env.insert(intern(name[]), ext);
|
|
||||||
if attr::contains_name(it.attrs[], "macro_export") {
|
|
||||||
fld.cx.exported_macros.push(it);
|
|
||||||
}
|
|
||||||
SmallVector::zero()
|
|
||||||
}
|
|
||||||
Right(Some(items)) => {
|
|
||||||
items.into_iter()
|
items.into_iter()
|
||||||
.map(|i| mark_item(i, fm))
|
.map(|i| mark_item(i, fm))
|
||||||
.flat_map(|i| fld.fold_item(i).into_iter())
|
.flat_map(|i| fld.fold_item(i).into_iter())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
Right(None) => {
|
None => {
|
||||||
fld.cx.span_err(path_span,
|
fld.cx.span_err(path_span,
|
||||||
format!("non-item macro in item position: {}",
|
format!("non-item macro in item position: {}",
|
||||||
extnamestr.get())[]);
|
extnamestr.get())[]);
|
||||||
|
@ -664,9 +677,6 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand a stmt
|
/// Expand a stmt
|
||||||
//
|
|
||||||
// I don't understand why this returns a vector... it looks like we're
|
|
||||||
// half done adding machinery to allow macros to expand into multiple statements.
|
|
||||||
fn expand_stmt(s: Stmt, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
|
fn expand_stmt(s: Stmt, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
|
||||||
let (mac, style) = match s.node {
|
let (mac, style) = match s.node {
|
||||||
StmtMac(mac, style) => (mac, style),
|
StmtMac(mac, style) => (mac, style),
|
||||||
|
@ -976,8 +986,8 @@ impl<'a> Folder for IdentRenamer<'a> {
|
||||||
ctxt: mtwt::apply_renames(self.renames, id.ctxt),
|
ctxt: mtwt::apply_renames(self.renames, id.ctxt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_mac(&mut self, macro: ast::Mac) -> ast::Mac {
|
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||||
fold::noop_fold_mac(macro, self)
|
fold::noop_fold_mac(mac, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,8 +1023,8 @@ impl<'a> Folder for PatIdentRenamer<'a> {
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn fold_mac(&mut self, macro: ast::Mac) -> ast::Mac {
|
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||||
fold::noop_fold_mac(macro, self)
|
fold::noop_fold_mac(mac, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1175,31 +1185,17 @@ impl ExpansionConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExportedMacros {
|
|
||||||
pub crate_name: Ident,
|
|
||||||
pub macros: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expand_crate(parse_sess: &parse::ParseSess,
|
pub fn expand_crate(parse_sess: &parse::ParseSess,
|
||||||
cfg: ExpansionConfig,
|
cfg: ExpansionConfig,
|
||||||
// these are the macros being imported to this crate:
|
// these are the macros being imported to this crate:
|
||||||
imported_macros: Vec<ExportedMacros>,
|
imported_macros: Vec<ast::MacroDef>,
|
||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
c: Crate) -> Crate {
|
c: Crate) -> Crate {
|
||||||
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
|
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
|
||||||
let mut expander = MacroExpander::new(&mut cx);
|
let mut expander = MacroExpander::new(&mut cx);
|
||||||
|
|
||||||
for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
|
for def in imported_macros.into_iter() {
|
||||||
let name = format!("<{} macros>", token::get_ident(crate_name));
|
expander.cx.insert_macro(def);
|
||||||
|
|
||||||
for source in macros.into_iter() {
|
|
||||||
let item = parse::parse_item_from_source_str(name.clone(),
|
|
||||||
source,
|
|
||||||
expander.cx.cfg(),
|
|
||||||
expander.cx.parse_sess())
|
|
||||||
.expect("expected a serialized item");
|
|
||||||
expand_item_mac(item, &mut expander);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, extension) in user_exts.into_iter() {
|
for (name, extension) in user_exts.into_iter() {
|
||||||
|
@ -1288,8 +1284,8 @@ struct MacroExterminator<'a>{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
|
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
|
||||||
fn visit_mac(&mut self, macro: &ast::Mac) {
|
fn visit_mac(&mut self, mac: &ast::Mac) {
|
||||||
self.sess.span_diagnostic.span_bug(macro.span,
|
self.sess.span_diagnostic.span_bug(mac.span,
|
||||||
"macro exterminator: expected AST \
|
"macro exterminator: expected AST \
|
||||||
with no macro invocations");
|
with no macro invocations");
|
||||||
}
|
}
|
||||||
|
@ -1298,7 +1294,7 @@ impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{pattern_bindings, expand_crate, contains_macro_escape};
|
use super::{pattern_bindings, expand_crate, contains_macro_use};
|
||||||
use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
|
use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
|
||||||
use ast;
|
use ast;
|
||||||
use ast::{Attribute_, AttrOuter, MetaWord, Name};
|
use ast::{Attribute_, AttrOuter, MetaWord, Name};
|
||||||
|
@ -1395,9 +1391,9 @@ mod test {
|
||||||
expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
|
expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
// macro_escape modules should allow macros to escape
|
// macro_use modules should allow macros to escape
|
||||||
#[test] fn macros_can_escape_flattened_mods_test () {
|
#[test] fn macros_can_escape_flattened_mods_test () {
|
||||||
let src = "#[macro_escape] mod foo {macro_rules! z (() => (3+4));}\
|
let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
|
||||||
fn inty() -> int { z!() }".to_string();
|
fn inty() -> int { z!() }".to_string();
|
||||||
let sess = parse::new_parse_sess();
|
let sess = parse::new_parse_sess();
|
||||||
let crate_ast = parse::parse_crate_from_source_str(
|
let crate_ast = parse::parse_crate_from_source_str(
|
||||||
|
@ -1407,16 +1403,6 @@ mod test {
|
||||||
expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast);
|
expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test] fn test_contains_flatten (){
|
|
||||||
let attr1 = make_dummy_attr ("foo");
|
|
||||||
let attr2 = make_dummy_attr ("bar");
|
|
||||||
let escape_attr = make_dummy_attr ("macro_escape");
|
|
||||||
let attrs1 = vec!(attr1.clone(), escape_attr, attr2.clone());
|
|
||||||
assert_eq!(contains_macro_escape(attrs1[]),true);
|
|
||||||
let attrs2 = vec!(attr1,attr2);
|
|
||||||
assert_eq!(contains_macro_escape(attrs2[]),false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make a MetaWord outer attribute with the given name
|
// make a MetaWord outer attribute with the given name
|
||||||
fn make_dummy_attr(s: &str) -> ast::Attribute {
|
fn make_dummy_attr(s: &str) -> ast::Attribute {
|
||||||
Spanned {
|
Spanned {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use ast::{Ident, TtDelimited, TtSequence, TtToken};
|
use ast::{Ident, TtDelimited, TtSequence, TtToken};
|
||||||
use ast;
|
use ast;
|
||||||
use codemap::{Span, DUMMY_SP};
|
use codemap::{Span, DUMMY_SP};
|
||||||
use ext::base::{ExtCtxt, MacResult, MacroDef};
|
use ext::base::{ExtCtxt, MacResult, SyntaxExtension};
|
||||||
use ext::base::{NormalTT, TTMacroExpander};
|
use ext::base::{NormalTT, TTMacroExpander};
|
||||||
use ext::tt::macro_parser::{Success, Error, Failure};
|
use ext::tt::macro_parser::{Success, Error, Failure};
|
||||||
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
||||||
|
@ -38,8 +38,8 @@ impl<'a> ParserAnyMacro<'a> {
|
||||||
/// Make sure we don't have any tokens left to parse, so we don't
|
/// Make sure we don't have any tokens left to parse, so we don't
|
||||||
/// silently drop anything. `allow_semi` is so that "optional"
|
/// silently drop anything. `allow_semi` is so that "optional"
|
||||||
/// semicolons at the end of normal expressions aren't complained
|
/// semicolons at the end of normal expressions aren't complained
|
||||||
/// about e.g. the semicolon in `macro_rules! kapow( () => {
|
/// about e.g. the semicolon in `macro_rules! kapow { () => {
|
||||||
/// panic!(); } )` doesn't get picked up by .parse_expr(), but it's
|
/// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
|
||||||
/// allowed to be there.
|
/// allowed to be there.
|
||||||
fn ensure_complete_parse(&self, allow_semi: bool) {
|
fn ensure_complete_parse(&self, allow_semi: bool) {
|
||||||
let mut parser = self.parser.borrow_mut();
|
let mut parser = self.parser.borrow_mut();
|
||||||
|
@ -110,6 +110,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||||
|
|
||||||
struct MacroRulesMacroExpander {
|
struct MacroRulesMacroExpander {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
|
imported_from: Option<Ident>,
|
||||||
lhses: Vec<Rc<NamedMatch>>,
|
lhses: Vec<Rc<NamedMatch>>,
|
||||||
rhses: Vec<Rc<NamedMatch>>,
|
rhses: Vec<Rc<NamedMatch>>,
|
||||||
}
|
}
|
||||||
|
@ -123,25 +124,18 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
||||||
generic_extension(cx,
|
generic_extension(cx,
|
||||||
sp,
|
sp,
|
||||||
self.name,
|
self.name,
|
||||||
|
self.imported_from,
|
||||||
arg,
|
arg,
|
||||||
self.lhses[],
|
self.lhses[],
|
||||||
self.rhses[])
|
self.rhses[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MacroRulesDefiner {
|
|
||||||
def: Option<MacroDef>
|
|
||||||
}
|
|
||||||
impl MacResult for MacroRulesDefiner {
|
|
||||||
fn make_def(&mut self) -> Option<MacroDef> {
|
|
||||||
Some(self.def.take().expect("empty MacroRulesDefiner"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given `lhses` and `rhses`, this is the new macro we create
|
/// Given `lhses` and `rhses`, this is the new macro we create
|
||||||
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
|
imported_from: Option<Ident>,
|
||||||
arg: &[ast::TokenTree],
|
arg: &[ast::TokenTree],
|
||||||
lhses: &[Rc<NamedMatch>],
|
lhses: &[Rc<NamedMatch>],
|
||||||
rhses: &[Rc<NamedMatch>])
|
rhses: &[Rc<NamedMatch>])
|
||||||
|
@ -165,6 +159,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||||
};
|
};
|
||||||
// `None` is because we're not interpolating
|
// `None` is because we're not interpolating
|
||||||
let mut arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
let mut arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||||
|
None,
|
||||||
None,
|
None,
|
||||||
arg.iter()
|
arg.iter()
|
||||||
.map(|x| (*x).clone())
|
.map(|x| (*x).clone())
|
||||||
|
@ -186,6 +181,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||||
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||||
Some(named_matches),
|
Some(named_matches),
|
||||||
|
imported_from,
|
||||||
rhs);
|
rhs);
|
||||||
let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
|
let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
|
||||||
// Let the context choose how to interpret the result.
|
// Let the context choose how to interpret the result.
|
||||||
|
@ -212,14 +208,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||||
//
|
//
|
||||||
// Holy self-referential!
|
// Holy self-referential!
|
||||||
|
|
||||||
/// This procedure performs the expansion of the
|
/// Converts a `macro_rules!` invocation into a syntax extension.
|
||||||
/// macro_rules! macro. It parses the RHS and adds
|
pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
|
||||||
/// an extension to the current context.
|
def: &ast::MacroDef) -> SyntaxExtension {
|
||||||
pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
|
||||||
sp: Span,
|
|
||||||
name: Ident,
|
|
||||||
arg: Vec<ast::TokenTree> )
|
|
||||||
-> Box<MacResult+'cx> {
|
|
||||||
|
|
||||||
let lhs_nm = gensym_ident("lhs");
|
let lhs_nm = gensym_ident("lhs");
|
||||||
let rhs_nm = gensym_ident("rhs");
|
let rhs_nm = gensym_ident("rhs");
|
||||||
|
@ -256,7 +247,8 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||||
// Parse the macro_rules! invocation (`none` is for no interpolations):
|
// Parse the macro_rules! invocation (`none` is for no interpolations):
|
||||||
let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||||
None,
|
None,
|
||||||
arg.clone());
|
None,
|
||||||
|
def.body.clone());
|
||||||
let argument_map = parse_or_else(cx.parse_sess(),
|
let argument_map = parse_or_else(cx.parse_sess(),
|
||||||
cx.cfg(),
|
cx.cfg(),
|
||||||
arg_reader,
|
arg_reader,
|
||||||
|
@ -265,24 +257,20 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||||
// Extract the arguments:
|
// Extract the arguments:
|
||||||
let lhses = match *argument_map[lhs_nm] {
|
let lhses = match *argument_map[lhs_nm] {
|
||||||
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
|
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
|
||||||
_ => cx.span_bug(sp, "wrong-structured lhs")
|
_ => cx.span_bug(def.span, "wrong-structured lhs")
|
||||||
};
|
};
|
||||||
|
|
||||||
let rhses = match *argument_map[rhs_nm] {
|
let rhses = match *argument_map[rhs_nm] {
|
||||||
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
|
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
|
||||||
_ => cx.span_bug(sp, "wrong-structured rhs")
|
_ => cx.span_bug(def.span, "wrong-structured rhs")
|
||||||
};
|
};
|
||||||
|
|
||||||
let exp = box MacroRulesMacroExpander {
|
let exp = box MacroRulesMacroExpander {
|
||||||
name: name,
|
name: def.ident,
|
||||||
|
imported_from: def.imported_from,
|
||||||
lhses: lhses,
|
lhses: lhses,
|
||||||
rhses: rhses,
|
rhses: rhses,
|
||||||
};
|
};
|
||||||
|
|
||||||
box MacroRulesDefiner {
|
NormalTT(exp, Some(def.span))
|
||||||
def: Some(MacroDef {
|
|
||||||
name: token::get_ident(name).to_string(),
|
|
||||||
ext: NormalTT(exp, Some(sp))
|
|
||||||
})
|
|
||||||
} as Box<MacResult+'cx>
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use codemap::{Span, DUMMY_SP};
|
||||||
use diagnostic::SpanHandler;
|
use diagnostic::SpanHandler;
|
||||||
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
||||||
use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt};
|
use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt};
|
||||||
use parse::token::{Token, NtIdent};
|
use parse::token::{Token, NtIdent, SpecialMacroVar};
|
||||||
use parse::token;
|
use parse::token;
|
||||||
use parse::lexer::TokenAndSpan;
|
use parse::lexer::TokenAndSpan;
|
||||||
|
|
||||||
|
@ -39,6 +39,10 @@ pub struct TtReader<'a> {
|
||||||
stack: Vec<TtFrame>,
|
stack: Vec<TtFrame>,
|
||||||
/* for MBE-style macro transcription */
|
/* for MBE-style macro transcription */
|
||||||
interpolations: HashMap<Ident, Rc<NamedMatch>>,
|
interpolations: HashMap<Ident, Rc<NamedMatch>>,
|
||||||
|
imported_from: Option<Ident>,
|
||||||
|
|
||||||
|
// Some => return imported_from as the next token
|
||||||
|
crate_name_next: Option<Span>,
|
||||||
repeat_idx: Vec<uint>,
|
repeat_idx: Vec<uint>,
|
||||||
repeat_len: Vec<uint>,
|
repeat_len: Vec<uint>,
|
||||||
/* cached: */
|
/* cached: */
|
||||||
|
@ -53,6 +57,7 @@ pub struct TtReader<'a> {
|
||||||
/// should) be none.
|
/// should) be none.
|
||||||
pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
|
pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
|
||||||
interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
|
interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
|
||||||
|
imported_from: Option<Ident>,
|
||||||
src: Vec<ast::TokenTree> )
|
src: Vec<ast::TokenTree> )
|
||||||
-> TtReader<'a> {
|
-> TtReader<'a> {
|
||||||
let mut r = TtReader {
|
let mut r = TtReader {
|
||||||
|
@ -71,6 +76,8 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
|
||||||
None => HashMap::new(),
|
None => HashMap::new(),
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
},
|
},
|
||||||
|
imported_from: imported_from,
|
||||||
|
crate_name_next: None,
|
||||||
repeat_idx: Vec::new(),
|
repeat_idx: Vec::new(),
|
||||||
repeat_len: Vec::new(),
|
repeat_len: Vec::new(),
|
||||||
desugar_doc_comments: false,
|
desugar_doc_comments: false,
|
||||||
|
@ -162,6 +169,14 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
|
||||||
sp: r.cur_span.clone(),
|
sp: r.cur_span.clone(),
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
|
match r.crate_name_next.take() {
|
||||||
|
None => (),
|
||||||
|
Some(sp) => {
|
||||||
|
r.cur_span = sp;
|
||||||
|
r.cur_tok = token::Ident(r.imported_from.unwrap(), token::Plain);
|
||||||
|
return ret_val;
|
||||||
|
},
|
||||||
|
}
|
||||||
let should_pop = match r.stack.last() {
|
let should_pop = match r.stack.last() {
|
||||||
None => {
|
None => {
|
||||||
assert_eq!(ret_val.tok, token::Eof);
|
assert_eq!(ret_val.tok, token::Eof);
|
||||||
|
@ -307,6 +322,18 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
|
||||||
sep: None
|
sep: None
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
TtToken(sp, token::SpecialVarNt(SpecialMacroVar::CrateMacroVar)) => {
|
||||||
|
r.stack.last_mut().unwrap().idx += 1;
|
||||||
|
|
||||||
|
if r.imported_from.is_some() {
|
||||||
|
r.cur_span = sp;
|
||||||
|
r.cur_tok = token::ModSep;
|
||||||
|
r.crate_name_next = Some(sp);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise emit nothing and proceed to the next token
|
||||||
|
}
|
||||||
TtToken(sp, tok) => {
|
TtToken(sp, tok) => {
|
||||||
r.cur_span = sp;
|
r.cur_span = sp;
|
||||||
r.cur_tok = tok;
|
r.cur_tok = tok;
|
||||||
|
|
|
@ -37,14 +37,14 @@ use std::ascii::AsciiExt;
|
||||||
// if you change this list without updating src/doc/reference.md, @cmr will be sad
|
// if you change this list without updating src/doc/reference.md, @cmr will be sad
|
||||||
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||||
("globs", Accepted),
|
("globs", Accepted),
|
||||||
("macro_rules", Active),
|
("macro_rules", Accepted),
|
||||||
("struct_variant", Accepted),
|
("struct_variant", Accepted),
|
||||||
("asm", Active),
|
("asm", Active),
|
||||||
("managed_boxes", Removed),
|
("managed_boxes", Removed),
|
||||||
("non_ascii_idents", Active),
|
("non_ascii_idents", Active),
|
||||||
("thread_local", Active),
|
("thread_local", Active),
|
||||||
("link_args", Active),
|
("link_args", Active),
|
||||||
("phase", Active),
|
("phase", Active), // NOTE(stage0): switch to Removed after next snapshot
|
||||||
("plugin_registrar", Active),
|
("plugin_registrar", Active),
|
||||||
("log_syntax", Active),
|
("log_syntax", Active),
|
||||||
("trace_macros", Active),
|
("trace_macros", Active),
|
||||||
|
@ -74,6 +74,8 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||||
("if_let", Accepted),
|
("if_let", Accepted),
|
||||||
("while_let", Accepted),
|
("while_let", Accepted),
|
||||||
|
|
||||||
|
("plugin", Active),
|
||||||
|
|
||||||
// A temporary feature gate used to enable parser extensions needed
|
// A temporary feature gate used to enable parser extensions needed
|
||||||
// to bootstrap fix for #5723.
|
// to bootstrap fix for #5723.
|
||||||
("issue_5723_bootstrap", Accepted),
|
("issue_5723_bootstrap", Accepted),
|
||||||
|
@ -161,32 +163,11 @@ struct MacroVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
|
impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
|
||||||
fn visit_view_item(&mut self, i: &ast::ViewItem) {
|
fn visit_mac(&mut self, mac: &ast::Mac) {
|
||||||
match i.node {
|
let ast::MacInvocTT(ref path, _, _) = mac.node;
|
||||||
ast::ViewItemExternCrate(..) => {
|
|
||||||
for attr in i.attrs.iter() {
|
|
||||||
if attr.name().get() == "phase"{
|
|
||||||
self.context.gate_feature("phase", attr.span,
|
|
||||||
"compile time crate loading is \
|
|
||||||
experimental and possibly buggy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
visit::walk_view_item(self, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_mac(&mut self, macro: &ast::Mac) {
|
|
||||||
let ast::MacInvocTT(ref path, _, _) = macro.node;
|
|
||||||
let id = path.segments.last().unwrap().identifier;
|
let id = path.segments.last().unwrap().identifier;
|
||||||
|
|
||||||
if id == token::str_to_ident("macro_rules") {
|
if id == token::str_to_ident("asm") {
|
||||||
self.context.gate_feature("macro_rules", path.span, "macro definitions are \
|
|
||||||
not stable enough for use and are subject to change");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if id == token::str_to_ident("asm") {
|
|
||||||
self.context.gate_feature("asm", path.span, "inline assembly is not \
|
self.context.gate_feature("asm", path.span, "inline assembly is not \
|
||||||
stable enough for use and is subject to change");
|
stable enough for use and is subject to change");
|
||||||
}
|
}
|
||||||
|
@ -233,10 +214,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
|
||||||
ast::ViewItemUse(..) => {}
|
ast::ViewItemUse(..) => {}
|
||||||
ast::ViewItemExternCrate(..) => {
|
ast::ViewItemExternCrate(..) => {
|
||||||
for attr in i.attrs.iter() {
|
for attr in i.attrs.iter() {
|
||||||
if attr.name().get() == "phase"{
|
if attr.check_name("plugin") {
|
||||||
self.gate_feature("phase", attr.span,
|
self.gate_feature("plugin", attr.span,
|
||||||
"compile time crate loading is \
|
"compiler plugins are experimental \
|
||||||
experimental and possibly buggy");
|
and possibly buggy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,13 +194,13 @@ pub trait Folder : Sized {
|
||||||
noop_fold_local(l, self)
|
noop_fold_local(l, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_mac(&mut self, _macro: Mac) -> Mac {
|
fn fold_mac(&mut self, _mac: Mac) -> Mac {
|
||||||
panic!("fold_mac disabled by default");
|
panic!("fold_mac disabled by default");
|
||||||
// NB: see note about macros above.
|
// NB: see note about macros above.
|
||||||
// if you really want a folder that
|
// if you really want a folder that
|
||||||
// works on macros, use this
|
// works on macros, use this
|
||||||
// definition in your trait impl:
|
// definition in your trait impl:
|
||||||
// fold::noop_fold_mac(_macro, self)
|
// fold::noop_fold_mac(_mac, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_explicit_self(&mut self, es: ExplicitSelf) -> ExplicitSelf {
|
fn fold_explicit_self(&mut self, es: ExplicitSelf) -> ExplicitSelf {
|
||||||
|
@ -1104,7 +1104,7 @@ pub fn noop_fold_mod<T: Folder>(Mod {inner, view_items, items}: Mod, folder: &mu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, config, exported_macros, span}: Crate,
|
pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, config, mut exported_macros, span}: Crate,
|
||||||
folder: &mut T) -> Crate {
|
folder: &mut T) -> Crate {
|
||||||
let config = folder.fold_meta_items(config);
|
let config = folder.fold_meta_items(config);
|
||||||
|
|
||||||
|
@ -1135,6 +1135,10 @@ pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, config, exported_macros,
|
||||||
}, Vec::new(), span)
|
}, Vec::new(), span)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for def in exported_macros.iter_mut() {
|
||||||
|
def.id = folder.new_id(def.id);
|
||||||
|
}
|
||||||
|
|
||||||
Crate {
|
Crate {
|
||||||
module: module,
|
module: module,
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
|
@ -1472,8 +1476,8 @@ mod test {
|
||||||
fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
|
fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
|
||||||
token::str_to_ident("zz")
|
token::str_to_ident("zz")
|
||||||
}
|
}
|
||||||
fn fold_mac(&mut self, macro: ast::Mac) -> ast::Mac {
|
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||||
fold::noop_fold_mac(macro, self)
|
fold::noop_fold_mac(mac, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,18 @@
|
||||||
|
|
||||||
extern crate arena;
|
extern crate arena;
|
||||||
extern crate fmt_macros;
|
extern crate fmt_macros;
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
extern crate "serialize" as rustc_serialize; // used by deriving
|
extern crate "serialize" as rustc_serialize; // used by deriving
|
||||||
|
|
||||||
pub mod util {
|
pub mod util {
|
||||||
|
|
|
@ -24,8 +24,11 @@ use std::num::Int;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
pub mod lexer;
|
#[cfg_attr(stage0, macro_escape)]
|
||||||
|
#[cfg_attr(not(stage0), macro_use)]
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
|
pub mod lexer;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
|
||||||
|
@ -166,6 +169,8 @@ pub fn parse_stmt_from_source_str(name: String,
|
||||||
|
|
||||||
// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
|
// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
|
||||||
// until #16472 is resolved.
|
// until #16472 is resolved.
|
||||||
|
//
|
||||||
|
// Warning: This parses with quote_depth > 0, which is not the default.
|
||||||
pub fn parse_tts_from_source_str(name: String,
|
pub fn parse_tts_from_source_str(name: String,
|
||||||
source: String,
|
source: String,
|
||||||
cfg: ast::CrateConfig,
|
cfg: ast::CrateConfig,
|
||||||
|
@ -291,7 +296,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
|
||||||
pub fn tts_to_parser<'a>(sess: &'a ParseSess,
|
pub fn tts_to_parser<'a>(sess: &'a ParseSess,
|
||||||
tts: Vec<ast::TokenTree>,
|
tts: Vec<ast::TokenTree>,
|
||||||
cfg: ast::CrateConfig) -> Parser<'a> {
|
cfg: ast::CrateConfig) -> Parser<'a> {
|
||||||
let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts);
|
let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts);
|
||||||
Parser::new(sess, cfg, box trdr)
|
Parser::new(sess, cfg, box trdr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +312,8 @@ pub mod with_hygiene {
|
||||||
|
|
||||||
// Note: keep this in sync with `super::parse_tts_from_source_str` until
|
// Note: keep this in sync with `super::parse_tts_from_source_str` until
|
||||||
// #16472 is resolved.
|
// #16472 is resolved.
|
||||||
|
//
|
||||||
|
// Warning: This parses with quote_depth > 0, which is not the default.
|
||||||
pub fn parse_tts_from_source_str(name: String,
|
pub fn parse_tts_from_source_str(name: String,
|
||||||
source: String,
|
source: String,
|
||||||
cfg: ast::CrateConfig,
|
cfg: ast::CrateConfig,
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![macro_escape]
|
|
||||||
|
|
||||||
pub use self::PathParsingMode::*;
|
pub use self::PathParsingMode::*;
|
||||||
use self::ItemOrViewItem::*;
|
use self::ItemOrViewItem::*;
|
||||||
|
|
||||||
|
@ -74,8 +72,8 @@ use parse::classify;
|
||||||
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
|
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
|
||||||
use parse::lexer::{Reader, TokenAndSpan};
|
use parse::lexer::{Reader, TokenAndSpan};
|
||||||
use parse::obsolete::*;
|
use parse::obsolete::*;
|
||||||
use parse::token::{self, MatchNt, SubstNt, InternedString};
|
use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
|
||||||
use parse::token::{keywords, special_idents};
|
use parse::token::{keywords, special_idents, SpecialMacroVar};
|
||||||
use parse::{new_sub_parser_from_file, ParseSess};
|
use parse::{new_sub_parser_from_file, ParseSess};
|
||||||
use print::pprust;
|
use print::pprust;
|
||||||
use ptr::P;
|
use ptr::P;
|
||||||
|
@ -2739,6 +2737,9 @@ impl<'a> Parser<'a> {
|
||||||
op: repeat,
|
op: repeat,
|
||||||
num_captures: name_num
|
num_captures: name_num
|
||||||
}))
|
}))
|
||||||
|
} else if p.token.is_keyword_allow_following_colon(keywords::Crate) {
|
||||||
|
p.bump();
|
||||||
|
TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))
|
||||||
} else {
|
} else {
|
||||||
// A nonterminal that matches or not
|
// A nonterminal that matches or not
|
||||||
let namep = match p.token { token::Ident(_, p) => p, _ => token::Plain };
|
let namep = match p.token { token::Ident(_, p) => p, _ => token::Plain };
|
||||||
|
@ -3881,13 +3882,13 @@ impl<'a> Parser<'a> {
|
||||||
&mut stmts,
|
&mut stmts,
|
||||||
&mut expr);
|
&mut expr);
|
||||||
}
|
}
|
||||||
StmtMac(macro, MacStmtWithoutBraces) => {
|
StmtMac(mac, MacStmtWithoutBraces) => {
|
||||||
// statement macro without braces; might be an
|
// statement macro without braces; might be an
|
||||||
// expr depending on whether a semicolon follows
|
// expr depending on whether a semicolon follows
|
||||||
match self.token {
|
match self.token {
|
||||||
token::Semi => {
|
token::Semi => {
|
||||||
stmts.push(P(Spanned {
|
stmts.push(P(Spanned {
|
||||||
node: StmtMac(macro,
|
node: StmtMac(mac,
|
||||||
MacStmtWithSemicolon),
|
MacStmtWithSemicolon),
|
||||||
span: span,
|
span: span,
|
||||||
}));
|
}));
|
||||||
|
@ -3896,10 +3897,16 @@ impl<'a> Parser<'a> {
|
||||||
_ => {
|
_ => {
|
||||||
let e = self.mk_mac_expr(span.lo,
|
let e = self.mk_mac_expr(span.lo,
|
||||||
span.hi,
|
span.hi,
|
||||||
|
<<<<<<< HEAD
|
||||||
macro.and_then(|m| m.node));
|
macro.and_then(|m| m.node));
|
||||||
let e = self.parse_dot_or_call_expr_with(e);
|
let e = self.parse_dot_or_call_expr_with(e);
|
||||||
let e = self.parse_more_binops(e, 0);
|
let e = self.parse_more_binops(e, 0);
|
||||||
let e = self.parse_assign_expr_with(e);
|
let e = self.parse_assign_expr_with(e);
|
||||||
|
=======
|
||||||
|
mac.and_then(|m| m.node));
|
||||||
|
let e =
|
||||||
|
self.parse_dot_or_call_expr_with(e);
|
||||||
|
>>>>>>> kmc/macro-reform
|
||||||
self.handle_expression_like_statement(
|
self.handle_expression_like_statement(
|
||||||
e,
|
e,
|
||||||
ast::DUMMY_NODE_ID,
|
ast::DUMMY_NODE_ID,
|
||||||
|
@ -6026,6 +6033,10 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_view_path(&mut self) -> P<ViewPath> {
|
fn parse_view_path(&mut self) -> P<ViewPath> {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
|
|
||||||
|
// Allow a leading :: because the paths are absolute either way.
|
||||||
|
// This occurs with "use $crate::..." in macros.
|
||||||
|
self.eat(&token::ModSep);
|
||||||
|
|
||||||
if self.check(&token::OpenDelim(token::Brace)) {
|
if self.check(&token::OpenDelim(token::Brace)) {
|
||||||
// use {foo,bar}
|
// use {foo,bar}
|
||||||
let idents = self.parse_unspanned_seq(
|
let idents = self.parse_unspanned_seq(
|
||||||
|
|
|
@ -61,6 +61,21 @@ pub enum IdentStyle {
|
||||||
Plain,
|
Plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)]
|
||||||
|
pub enum SpecialMacroVar {
|
||||||
|
/// `$crate` will be filled in with the name of the crate a macro was
|
||||||
|
/// imported from, if any.
|
||||||
|
CrateMacroVar,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecialMacroVar {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
SpecialMacroVar::CrateMacroVar => "crate",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)]
|
||||||
pub enum Lit {
|
pub enum Lit {
|
||||||
Byte(ast::Name),
|
Byte(ast::Name),
|
||||||
|
@ -143,6 +158,8 @@ pub enum Token {
|
||||||
// In right-hand-sides of MBE macros:
|
// In right-hand-sides of MBE macros:
|
||||||
/// A syntactic variable that will be filled in by macro expansion.
|
/// A syntactic variable that will be filled in by macro expansion.
|
||||||
SubstNt(ast::Ident, IdentStyle),
|
SubstNt(ast::Ident, IdentStyle),
|
||||||
|
/// A macro variable with special meaning.
|
||||||
|
SpecialVarNt(SpecialMacroVar),
|
||||||
|
|
||||||
// Junk. These carry no data because we don't really care about the data
|
// Junk. These carry no data because we don't really care about the data
|
||||||
// they *would* carry, and don't really want to allocate a new ident for
|
// they *would* carry, and don't really want to allocate a new ident for
|
||||||
|
@ -265,6 +282,13 @@ impl Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_keyword_allow_following_colon(&self, kw: keywords::Keyword) -> bool {
|
||||||
|
match *self {
|
||||||
|
Ident(sid, _) => { kw.to_name() == sid.name }
|
||||||
|
_ => { false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token is either a special identifier, or a strict
|
/// Returns `true` if the token is either a special identifier, or a strict
|
||||||
/// or reserved keyword.
|
/// or reserved keyword.
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
|
@ -550,6 +574,7 @@ declare_special_idents_and_keywords! {
|
||||||
(56, Abstract, "abstract");
|
(56, Abstract, "abstract");
|
||||||
(57, Final, "final");
|
(57, Final, "final");
|
||||||
(58, Override, "override");
|
(58, Override, "override");
|
||||||
|
(59, Macro, "macro");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue