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
|
@ -15,7 +15,14 @@
|
|||
|
||||
extern crate test;
|
||||
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;
|
||||
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
% 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
|
||||
|
||||
Functions are the primary tool that programmers can use to build abstractions.
|
||||
|
@ -46,19 +37,18 @@ lightweight custom syntax extensions, themselves defined using the
|
|||
the pattern in the above code:
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# enum T { SpecialA(uint), SpecialB(uint) }
|
||||
# fn f() -> uint {
|
||||
# let input_1 = T::SpecialA(0);
|
||||
# let input_2 = T::SpecialA(0);
|
||||
macro_rules! early_return(
|
||||
macro_rules! early_return {
|
||||
($inp:expr $sp:path) => ( // invoke it like `(input_5 SpecialE)`
|
||||
match $inp {
|
||||
$sp(x) => { return x; }
|
||||
_ => {}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
// ...
|
||||
early_return!(input_1 T::SpecialA);
|
||||
// ...
|
||||
|
@ -109,10 +99,10 @@ that could be invoked like: `my_macro!(i->(( 2+2 )))`.
|
|||
|
||||
## Invocation location
|
||||
|
||||
A macro invocation may take the place of (and therefore expand to)
|
||||
an expression, an item, or a statement.
|
||||
The Rust parser will parse the macro invocation as a "placeholder"
|
||||
for whichever of those three nonterminals is appropriate for the location.
|
||||
A macro invocation may take the place of (and therefore expand to) an
|
||||
expression, item, statement, or pattern. The Rust parser will parse the macro
|
||||
invocation as a "placeholder" for whichever syntactic form is appropriate for
|
||||
the location.
|
||||
|
||||
At expansion time, the output of the macro will be parsed as whichever of the
|
||||
three nonterminals it stands in for. This means that a single macro might,
|
||||
|
@ -166,12 +156,11 @@ separator token (a comma-separated list could be written `$(...),*`), and `+`
|
|||
instead of `*` to mean "at least one".
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)}
|
||||
# fn f() -> uint {
|
||||
# let input_1 = T::SpecialA(0);
|
||||
# let input_2 = T::SpecialA(0);
|
||||
macro_rules! early_return(
|
||||
macro_rules! early_return {
|
||||
($inp:expr, [ $($sp:path)|+ ]) => (
|
||||
match $inp {
|
||||
$(
|
||||
|
@ -180,7 +169,7 @@ macro_rules! early_return(
|
|||
_ => {}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
// ...
|
||||
early_return!(input_1, [T::SpecialA|T::SpecialC|T::SpecialD]);
|
||||
// ...
|
||||
|
@ -228,7 +217,6 @@ solves the problem.
|
|||
Now consider code like the following:
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# enum T1 { Good1(T2, uint), Bad1}
|
||||
# struct T2 { body: T3 }
|
||||
# enum T3 { Good2(uint), Bad2}
|
||||
|
@ -255,8 +243,7 @@ a match, but with a syntax that suits the problem better. The following macro
|
|||
can solve the problem:
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
macro_rules! biased_match (
|
||||
macro_rules! biased_match {
|
||||
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
||||
( ($e:expr) ~ ($p:pat) else $err:stmt ;
|
||||
binds $bind_res:ident
|
||||
|
@ -275,7 +262,7 @@ macro_rules! biased_match (
|
|||
_ => { $err }
|
||||
};
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
# enum T1 { Good1(T2, uint), Bad1}
|
||||
# struct T2 { body: T3 }
|
||||
|
@ -297,13 +284,12 @@ like this, we might prefer to write a single macro invocation. The input
|
|||
pattern we want is clear:
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# fn main() {}
|
||||
# macro_rules! b(
|
||||
# macro_rules! b {
|
||||
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
)
|
||||
# => (0));
|
||||
# => (0) }
|
||||
~~~~
|
||||
|
||||
However, it's not possible to directly expand to nested match statements. But
|
||||
|
@ -320,24 +306,22 @@ process the semicolon-terminated lines, one-by-one. So, we want the following
|
|||
input patterns:
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# macro_rules! b(
|
||||
# macro_rules! b {
|
||||
( binds $( $bind_res:ident ),* )
|
||||
# => (0));
|
||||
# => (0) }
|
||||
# fn main() {}
|
||||
~~~~
|
||||
|
||||
...and:
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# fn main() {}
|
||||
# macro_rules! b(
|
||||
# macro_rules! b {
|
||||
( ($e :expr) ~ ($p :pat) else $err :stmt ;
|
||||
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
)
|
||||
# => (0));
|
||||
# => (0) }
|
||||
~~~~
|
||||
|
||||
The resulting macro looks like this. Note that the separation into
|
||||
|
@ -345,10 +329,9 @@ The resulting macro looks like this. Note that the separation into
|
|||
piece of syntax (the `let`) which we only want to transcribe once.
|
||||
|
||||
~~~~
|
||||
# #![feature(macro_rules)]
|
||||
# fn main() {
|
||||
|
||||
macro_rules! biased_match_rec (
|
||||
macro_rules! biased_match_rec {
|
||||
// Handle the first layer
|
||||
( ($e :expr) ~ ($p :pat) else $err :stmt ;
|
||||
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
||||
|
@ -366,10 +349,10 @@ macro_rules! biased_match_rec (
|
|||
);
|
||||
// Produce the requested values
|
||||
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
|
||||
);
|
||||
}
|
||||
|
||||
// Wrap the whole thing in a `let`.
|
||||
macro_rules! biased_match (
|
||||
macro_rules! biased_match {
|
||||
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
||||
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
||||
binds $bind_res:ident
|
||||
|
@ -388,7 +371,7 @@ macro_rules! biased_match (
|
|||
binds $( $bind_res ),*
|
||||
);
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
# enum T1 { Good1(T2, uint), Bad1}
|
||||
|
@ -434,9 +417,7 @@ As an example, `loop` and `for-loop` labels (discussed in the lifetimes guide)
|
|||
will not clash. The following code will print "Hello!" only once:
|
||||
|
||||
~~~
|
||||
#![feature(macro_rules)]
|
||||
|
||||
macro_rules! loop_x (
|
||||
macro_rules! loop_x {
|
||||
($e: expr) => (
|
||||
// $e will not interact with this 'x
|
||||
'x: loop {
|
||||
|
@ -444,7 +425,7 @@ macro_rules! loop_x (
|
|||
$e
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
'x: loop {
|
||||
|
@ -467,22 +448,30 @@ lexical-order traversal of a crate's source. So a macro defined at module scope
|
|||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
If a module has the `macro_escape` attribute, its macros are also visible in
|
||||
its parent module after the child's `mod` item. If the parent also has
|
||||
`macro_escape` then the macros will be visible in the grandparent after the
|
||||
parent's `mod` item, and so forth.
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
Independent of `macro_escape`, the `macro_export` attribute controls visibility
|
||||
between crates. Any `macro_rules!` definition with the `macro_export`
|
||||
attribute will be visible to other crates that have loaded this crate with
|
||||
`phase(plugin)`. There is currently no way for the importing crate to control
|
||||
which macros are imported.
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
# #![feature(macro_rules)]
|
||||
macro_rules! m1 (() => (()));
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
|
@ -490,22 +479,22 @@ mod foo {
|
|||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 (() => (()));
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 (() => (()));
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_escape]
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 (() => (()));
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
@ -514,8 +503,58 @@ mod bar {
|
|||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[phase(plugin)] extern crate`, only `m2`
|
||||
will be imported.
|
||||
When this library is loaded with `#[use_macros] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
|
||||
```rust
|
||||
pub fn increment(x: uint) -> uint {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
|
||||
To keep this system simple and correct, `#[macro_use] extern crate ...` may
|
||||
only appear at the root of your crate, not inside `mod`. This ensures that
|
||||
`$crate` is a single identifier.
|
||||
|
||||
# A final note
|
||||
|
||||
|
|
|
@ -31,10 +31,14 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc.
|
|||
|
||||
A plugin is a dynamic library crate with a designated "registrar" function that
|
||||
registers extensions with `rustc`. Other crates can use these extensions by
|
||||
loading the plugin crate with `#[phase(plugin)] extern crate`. See the
|
||||
loading the plugin crate with `#[plugin] extern crate`. See the
|
||||
[`rustc::plugin`](rustc/plugin/index.html) documentation for more about the
|
||||
mechanics of defining and loading a plugin.
|
||||
|
||||
Arguments passed as `#[plugin=...]` or `#[plugin(...)]` are not interpreted by
|
||||
rustc itself. They are provided to the plugin through the `Registry`'s [`args`
|
||||
method](rustc/plugin/registry/struct.Registry.html#method.args).
|
||||
|
||||
# Syntax extensions
|
||||
|
||||
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
||||
|
@ -105,10 +109,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||
Then we can use `rn!()` like any other macro:
|
||||
|
||||
```ignore
|
||||
#![feature(phase)]
|
||||
#![feature(plugin)]
|
||||
|
||||
#[phase(plugin)]
|
||||
extern crate roman_numerals;
|
||||
#[plugin] extern crate roman_numerals;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(rn!(MMXV), 2015);
|
||||
|
@ -217,8 +220,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||
Then code like
|
||||
|
||||
```ignore
|
||||
#[phase(plugin)]
|
||||
extern crate lint_plugin_test;
|
||||
#[plugin] extern crate lint_plugin_test;
|
||||
|
||||
fn lintme() { }
|
||||
```
|
||||
|
|
|
@ -193,12 +193,12 @@ grammar as double-quoted strings. Other tokens have exact rules given.
|
|||
| break | const | continue | crate | do |
|
||||
| else | enum | extern | false | final |
|
||||
| fn | for | if | impl | in |
|
||||
| let | loop | match | mod | move |
|
||||
| mut | offsetof | override | priv | pub |
|
||||
| pure | ref | return | sizeof | static |
|
||||
| self | struct | super | true | trait |
|
||||
| type | typeof | unsafe | unsized | use |
|
||||
| virtual | where | while | yield |
|
||||
| let | loop | macro | match | mod |
|
||||
| move | mut | offsetof | override | priv |
|
||||
| pub | pure | ref | return | sizeof |
|
||||
| static | self | struct | super | true |
|
||||
| trait | type | typeof | unsafe | unsized |
|
||||
| use | virtual | where | while | yield |
|
||||
|
||||
|
||||
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 ;
|
||||
```
|
||||
|
||||
User-defined syntax extensions are called "macros", and the `macro_rules`
|
||||
syntax extension defines them. Currently, user-defined macros can expand to
|
||||
expressions, statements, items, or patterns.
|
||||
`macro_rules` allows users to define syntax extension in a declarative way. We
|
||||
call such extensions "macros by example" or simply "macros" — to be distinguished
|
||||
from the "procedural macros" defined in [compiler plugins][plugin].
|
||||
|
||||
Currently, macros can expand to expressions, statements, items, or patterns.
|
||||
|
||||
(A `sep_token` is any token other than `*` and `+`. A `non_special_token` is
|
||||
any token other than a delimiter or `$`.)
|
||||
|
@ -2002,8 +2004,6 @@ type int8_t = i8;
|
|||
|
||||
### Module-only attributes
|
||||
|
||||
- `macro_escape` - macros defined in this module will be visible in the
|
||||
module's parent, after this module has been included.
|
||||
- `no_implicit_prelude` - disable injecting `use std::prelude::*` in this
|
||||
module.
|
||||
- `path` - specifies the file to load the module from. `#[path="foo.rs"] mod
|
||||
|
@ -2066,23 +2066,43 @@ On `struct`s:
|
|||
remove any padding between fields (note that this is very fragile and may
|
||||
break platforms which require aligned access).
|
||||
|
||||
### Macro- and plugin-related attributes
|
||||
|
||||
- `macro_use` on a `mod` — macros defined in this module will be visible in the
|
||||
module's parent, after this module has been included.
|
||||
|
||||
- `macro_use` on an `extern crate` — load macros from this crate. An optional
|
||||
list of names `#[macro_use(foo, bar)]` restricts the import to just those
|
||||
macros named. The `extern crate` must appear at the crate root, not inside
|
||||
`mod`, which ensures proper function of the [`$crate` macro
|
||||
variable](guide-macros.html#the-variable-$crate).
|
||||
|
||||
- `macro_reexport` on an `extern crate` — re-export the named macros.
|
||||
|
||||
- `macro_export` - export a macro for cross-crate usage.
|
||||
|
||||
- `plugin` on an `extern crate` — load this crate as a [compiler
|
||||
plugin][plugin]. The `plugin` feature gate is required. Any arguments to
|
||||
the attribute, e.g. `#[plugin=...]` or `#[plugin(...)]`, are provided to the
|
||||
plugin.
|
||||
|
||||
- `no_link` on an `extern crate` — even if we load this crate for macros or
|
||||
compiler plugins, don't link it into the output.
|
||||
|
||||
See the [macros guide](guide-macros.html#scoping-and-macro-import/export) for
|
||||
more information on macro scope.
|
||||
|
||||
|
||||
### Miscellaneous attributes
|
||||
|
||||
- `export_name` - on statics and functions, this determines the name of the
|
||||
exported symbol.
|
||||
- `link_section` - on statics and functions, this specifies the section of the
|
||||
object file that this item's contents will be placed into.
|
||||
- `macro_export` - export a macro for cross-crate usage.
|
||||
- `no_mangle` - on any item, do not apply the standard name mangling. Set the
|
||||
symbol for this item to its identifier.
|
||||
- `packed` - on structs or enums, eliminate any padding that would be used to
|
||||
align fields.
|
||||
- `phase` - on `extern crate` statements, allows specifying which "phase" of
|
||||
compilation the crate should be loaded for. Currently, there are two
|
||||
choices: `link` and `plugin`. `link` is the default. `plugin` will [load the
|
||||
crate at compile-time][plugin] and use any syntax extensions or lints that the crate
|
||||
defines. They can both be specified, `#[phase(link, plugin)]` to use a crate
|
||||
both at runtime and compiletime.
|
||||
- `simd` - on certain tuple structs, derive the arithmetic operators, which
|
||||
lower to the target's SIMD instructions, if any; the `simd` feature gate
|
||||
is necessary to use this attribute.
|
||||
|
@ -2569,15 +2589,6 @@ The currently implemented features of the reference compiler are:
|
|||
* `log_syntax` - Allows use of the `log_syntax` macro attribute, which is a
|
||||
nasty hack that will certainly be removed.
|
||||
|
||||
* `macro_rules` - The definition of new macros. This does not encompass
|
||||
macro-invocation, that is always enabled by default, this
|
||||
only covers the definition of new macros. There are currently
|
||||
various problems with invoking macros, how they interact with
|
||||
their environment, and possibly how they are used outside of
|
||||
location in which they are defined. Macro definitions are
|
||||
likely to change slightly in the future, so they are
|
||||
currently hidden behind this feature.
|
||||
|
||||
* `non_ascii_idents` - The compiler supports the use of non-ascii identifiers,
|
||||
but the implementation is a little rough around the
|
||||
edges, so this can be seen as an experimental feature
|
||||
|
@ -2588,15 +2599,10 @@ The currently implemented features of the reference compiler are:
|
|||
closure as `once` is unlikely to be supported going forward. So
|
||||
they are hidden behind this feature until they are to be removed.
|
||||
|
||||
* `phase` - Usage of the `#[phase]` attribute allows loading compiler plugins
|
||||
for custom lints or syntax extensions. The implementation is
|
||||
considered unwholesome and in need of overhaul, and it is not clear
|
||||
what they will look like moving forward.
|
||||
* `plugin` - Usage of [compiler plugins][plugin] for custom lints or syntax extensions.
|
||||
These depend on compiler internals and are subject to change.
|
||||
|
||||
* `plugin_registrar` - Indicates that a crate has [compiler plugins][plugin] that it
|
||||
wants to load. As with `phase`, the implementation is
|
||||
in need of an overhaul, and it is not clear that plugins
|
||||
defined using this will continue to work.
|
||||
* `plugin_registrar` - Indicates that a crate provides [compiler plugins][plugin].
|
||||
|
||||
* `quote` - Allows use of the `quote_*!` family of macros, which are
|
||||
implemented very poorly and will likely change significantly
|
||||
|
|
|
@ -56,7 +56,7 @@ syn match rustMacroRepeatCount ".\?[*+]" contained
|
|||
syn match rustMacroVariable "$\w\+"
|
||||
|
||||
" Reserved (but not yet used) keywords {{{2
|
||||
syn keyword rustReservedKeyword alignof be do offsetof priv pure sizeof typeof unsized yield abstract final override
|
||||
syn keyword rustReservedKeyword alignof be do offsetof priv pure sizeof typeof unsized yield abstract final override macro
|
||||
|
||||
" Built-in types {{{2
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(globs, phase, macro_rules)]
|
||||
#![feature(globs, plugin)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate rustc;
|
||||
|
||||
#[phase(link)]
|
||||
extern crate regex;
|
||||
|
||||
#[phase(link, plugin)]
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -269,7 +268,7 @@ fn main() {
|
|||
assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
|
||||
antlr_tok);
|
||||
|
||||
macro_rules! matches (
|
||||
macro_rules! matches {
|
||||
( $($x:pat),+ ) => (
|
||||
match rustc_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)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
matches!(
|
||||
token::Literal(token::Byte(..), _),
|
||||
|
|
|
@ -68,14 +68,33 @@
|
|||
#![feature(lang_items, phase, unsafe_destructor, default_type_params, old_orphan_check)]
|
||||
#![feature(associated_types)]
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[phase(plugin, link)]
|
||||
extern crate core;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[macro_use]
|
||||
extern crate core;
|
||||
|
||||
extern crate libc;
|
||||
|
||||
// Allow testing this library
|
||||
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate std;
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
||||
#[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;
|
||||
|
||||
// Heaps provided for low-level allocation strategies
|
||||
|
||||
|
|
|
@ -29,15 +29,34 @@
|
|||
#![feature(associated_types)]
|
||||
#![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 alloc;
|
||||
|
||||
#[cfg(test)] extern crate test;
|
||||
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate std;
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
||||
#[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;
|
||||
|
||||
pub use binary_heap::BinaryHeap;
|
||||
pub use bitv::Bitv;
|
||||
|
@ -51,6 +70,11 @@ pub use string::String;
|
|||
pub use vec::Vec;
|
||||
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;
|
||||
|
||||
pub mod binary_heap;
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
/// Creates a `std::vec::Vec` containing the arguments.
|
||||
// NOTE: remove after the next snapshot
|
||||
#[cfg(stage0)]
|
||||
macro_rules! vec {
|
||||
($($e:expr),*) => ({
|
||||
// leading _ to allow empty construction without a warning.
|
||||
|
@ -21,3 +21,13 @@ macro_rules! vec {
|
|||
($($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]
|
||||
fn test_show() {
|
||||
macro_rules! test_show_vec(
|
||||
macro_rules! test_show_vec {
|
||||
($x:expr, $x_str:expr) => ({
|
||||
let (x, x_str) = ($x, $x_str);
|
||||
assert_eq!(format!("{}", x), x_str);
|
||||
assert_eq!(format!("{}", x.as_slice()), x_str);
|
||||
})
|
||||
);
|
||||
}
|
||||
let empty: Vec<int> = vec![];
|
||||
test_show_vec!(empty, "[]");
|
||||
test_show_vec!(vec![1i], "[1]");
|
||||
|
@ -2624,12 +2624,12 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_vec_default() {
|
||||
macro_rules! t (
|
||||
macro_rules! t {
|
||||
($ty:ty) => {{
|
||||
let v: $ty = Default::default();
|
||||
assert!(v.is_empty());
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
t!(&[int]);
|
||||
t!(Vec<int>);
|
||||
|
|
|
@ -1846,7 +1846,9 @@ mod tests {
|
|||
#[test]
|
||||
fn test_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
|
||||
pos!(&[0x0000],
|
||||
|
@ -1866,7 +1868,9 @@ mod tests {
|
|||
&[0x0067, 0xd8ff, 0xddb7, 0x000f, 0xd900, 0xdc80]);
|
||||
|
||||
// negative tests
|
||||
macro_rules! neg ( ($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } });
|
||||
macro_rules! neg {
|
||||
($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } }
|
||||
}
|
||||
|
||||
neg!(
|
||||
// surrogate + regular unit
|
||||
|
|
|
@ -182,7 +182,7 @@ impl String {
|
|||
let byte = unsafe_get(v, i);
|
||||
i += 1;
|
||||
|
||||
macro_rules! error(() => ({
|
||||
macro_rules! error { () => ({
|
||||
unsafe {
|
||||
if subseqidx != i_ {
|
||||
res.as_mut_vec().push_all(v[subseqidx..i_]);
|
||||
|
@ -190,7 +190,7 @@ impl String {
|
|||
subseqidx = i;
|
||||
res.as_mut_vec().push_all(REPLACEMENT);
|
||||
}
|
||||
}));
|
||||
})}
|
||||
|
||||
if byte < 128u8 {
|
||||
// subseqidx handles this
|
||||
|
|
|
@ -20,12 +20,15 @@ use mem;
|
|||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
use ops::{Deref, FnOnce};
|
||||
use result::Result::{Ok, Err};
|
||||
use result::Result::Ok;
|
||||
use result;
|
||||
use slice::SliceExt;
|
||||
use slice;
|
||||
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::RadixFmt;
|
||||
|
|
|
@ -62,11 +62,24 @@
|
|||
#![feature(default_type_params, unboxed_closures, associated_types)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
mod macros;
|
||||
|
||||
#[path = "num/float_macros.rs"] mod float_macros;
|
||||
#[path = "num/int_macros.rs"] mod int_macros;
|
||||
#[path = "num/uint_macros.rs"] mod uint_macros;
|
||||
#[path = "num/float_macros.rs"]
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[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/i8.rs"] pub mod i8;
|
||||
|
@ -130,6 +143,7 @@ mod array;
|
|||
#[doc(hidden)]
|
||||
mod core {
|
||||
pub use panicking;
|
||||
pub use fmt;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
/// Entry point of task panic, for details, see std::macros
|
||||
#[macro_export]
|
||||
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_rules! assert {
|
||||
($cond:expr) => (
|
||||
|
@ -38,61 +55,197 @@ macro_rules! assert {
|
|||
panic!(concat!("assertion failed: ", stringify!($cond)))
|
||||
}
|
||||
);
|
||||
($cond:expr, $($arg:tt)*) => (
|
||||
($cond:expr, $($arg:expr),+) => (
|
||||
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_rules! assert_eq {
|
||||
($cond1:expr, $cond2:expr) => ({
|
||||
let c1 = $cond1;
|
||||
let c2 = $cond2;
|
||||
if c1 != c2 || c2 != c1 {
|
||||
panic!("expressions not equal, left: {}, right: {}", c1, c2);
|
||||
($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)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Runtime assertion for equality, only without `--cfg ndebug`
|
||||
#[macro_export]
|
||||
macro_rules! debug_assert_eq {
|
||||
($($a:tt)*) => ({
|
||||
if cfg!(not(ndebug)) {
|
||||
assert_eq!($($a)*);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Runtime assertion, disableable at compile time with `--cfg ndebug`
|
||||
/// 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)*); })
|
||||
}
|
||||
|
||||
/// 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_rules! try {
|
||||
($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_rules! write {
|
||||
($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]
|
||||
#[stable]
|
||||
macro_rules! writeln {
|
||||
($dst:expr, $fmt:expr $($arg:tt)*) => (
|
||||
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_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
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! assert_approx_eq {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! int_module { ($T:ty, $bits:expr) => (
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (
|
||||
|
|
|
@ -220,9 +220,9 @@
|
|||
//!
|
||||
//! ```
|
||||
//! # #![feature(macro_rules)]
|
||||
//! macro_rules! try(
|
||||
//! macro_rules! try {
|
||||
//! ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
||||
//! );
|
||||
//! }
|
||||
//! # fn main() { }
|
||||
//! ```
|
||||
//!
|
||||
|
|
|
@ -964,17 +964,18 @@ fn run_utf8_validation_iterator(iter: &mut slice::Iter<u8>)
|
|||
let old = *iter;
|
||||
|
||||
// restore the iterator we had at the start of this codepoint.
|
||||
macro_rules! err (() => { {
|
||||
macro_rules! err { () => {{
|
||||
*iter = old;
|
||||
return Err(Utf8Error::InvalidByte(whole.len() - iter.as_slice().len()))
|
||||
} });
|
||||
macro_rules! next ( () => {
|
||||
}}}
|
||||
|
||||
macro_rules! next { () => {
|
||||
match iter.next() {
|
||||
Some(a) => *a,
|
||||
// we needed data, but there was none: error!
|
||||
None => return Err(Utf8Error::TooShort),
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
let first = match iter.next() {
|
||||
Some(&b) => b,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![feature(globs, unsafe_destructor, macro_rules, slicing_syntax, default_type_params)]
|
||||
#![feature(globs, unsafe_destructor, slicing_syntax, default_type_params)]
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
extern crate core;
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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)]
|
||||
mod tests {
|
||||
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::kinds::Copy;
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
mod int_macros;
|
||||
|
||||
mod i8;
|
||||
mod i16;
|
||||
mod i32;
|
||||
mod i64;
|
||||
mod int;
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
mod uint_macros;
|
||||
|
||||
mod u8;
|
||||
mod u16;
|
||||
mod u32;
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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)]
|
||||
mod tests {
|
||||
use core::$T_i::*;
|
||||
|
@ -125,4 +123,5 @@ mod tests {
|
|||
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",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
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;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
|
||||
#![feature(macro_rules, globs, slicing_syntax)]
|
||||
#![feature(globs, slicing_syntax)]
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub use self::Piece::*;
|
||||
|
|
|
@ -85,11 +85,11 @@
|
|||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![feature(globs, phase, slicing_syntax)]
|
||||
#![feature(globs, slicing_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
||||
#[cfg(test)] #[macro_use] extern crate log;
|
||||
|
||||
use self::Name::*;
|
||||
use self::HasArg::*;
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! #![feature(phase)]
|
||||
//! #[phase(plugin, link)] extern crate log;
|
||||
//! #[macro_use] extern crate log;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! debug!("this is a debug {}", "message");
|
||||
|
@ -183,7 +182,10 @@ use regex::Regex;
|
|||
|
||||
use directive::LOG_LEVEL_NAMES;
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
pub mod macros;
|
||||
|
||||
mod directive;
|
||||
|
||||
/// Maximum logging level of a module that can be specified. Common logging
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
//! Logging macros
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
/// The standard logging macro
|
||||
///
|
||||
/// This macro will generically log over a provided level (of type u32) with a
|
||||
|
@ -21,8 +19,7 @@
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(phase)]
|
||||
/// #[phase(plugin, link)] extern crate log;
|
||||
/// #[macro_use] extern crate log;
|
||||
///
|
||||
/// fn main() {
|
||||
/// log!(log::WARN, "this is a warning {}", "message");
|
||||
|
@ -70,8 +67,7 @@ macro_rules! log {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(phase)]
|
||||
/// #[phase(plugin, link)] extern crate log;
|
||||
/// #[macro_use] extern crate log;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let error = 3u;
|
||||
|
@ -96,8 +92,7 @@ macro_rules! error {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(phase)]
|
||||
/// #[phase(plugin, link)] extern crate log;
|
||||
/// #[macro_use] extern crate log;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let code = 3u;
|
||||
|
@ -121,8 +116,7 @@ macro_rules! warn {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(phase)]
|
||||
/// #[phase(plugin, link)] extern crate log;
|
||||
/// #[macro_use] extern crate log;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let ret = 3;
|
||||
|
@ -148,8 +142,7 @@ macro_rules! info {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(phase)]
|
||||
/// #[phase(plugin, link)] extern crate log;
|
||||
/// #[macro_use] extern crate log;
|
||||
///
|
||||
/// fn main() {
|
||||
/// debug!("x = {x}, y = {y}", x=10, y=20);
|
||||
|
@ -172,8 +165,7 @@ macro_rules! debug {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(phase)]
|
||||
/// #[phase(plugin, link)] extern crate log;
|
||||
/// #[macro_use] extern crate log;
|
||||
///
|
||||
/// struct Point { x: int, y: int }
|
||||
/// 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
|
||||
// 1, internally; modulo a modulo operation).
|
||||
|
||||
macro_rules! t (
|
||||
macro_rules! t {
|
||||
($items:expr, $expected:expr) => {{
|
||||
let mut items = $items;
|
||||
let wc = WeightedChoice::new(items.as_mut_slice());
|
||||
|
@ -309,7 +309,7 @@ mod tests {
|
|||
assert_eq!(wc.ind_sample(&mut rng), val)
|
||||
}
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
t!(vec!(Weighted { weight: 1, item: 10i}), [10]);
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_integers() {
|
||||
let mut rng = ::test::rng();
|
||||
macro_rules! t (
|
||||
macro_rules! t {
|
||||
($($ty:ty),*) => {{
|
||||
$(
|
||||
let v: &[($ty, $ty)] = &[(0, 10),
|
||||
|
@ -199,7 +199,7 @@ mod tests {
|
|||
}
|
||||
)*
|
||||
}}
|
||||
);
|
||||
}
|
||||
t!(i8, i16, i32, i64, int,
|
||||
u8, u16, u32, u64, uint)
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_floats() {
|
||||
let mut rng = ::test::rng();
|
||||
macro_rules! t (
|
||||
macro_rules! t {
|
||||
($($ty:ty),*) => {{
|
||||
$(
|
||||
let v: &[($ty, $ty)] = &[(0.0, 100.0),
|
||||
|
@ -225,7 +225,7 @@ mod tests {
|
|||
}
|
||||
)*
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
t!(f32, f64)
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ impl IsaacRng {
|
|||
let mut g = a;
|
||||
let mut h = a;
|
||||
|
||||
macro_rules! mix(
|
||||
macro_rules! mix {
|
||||
() => {{
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=c>>2; e+=b; c+=d;
|
||||
|
@ -80,14 +80,14 @@ impl IsaacRng {
|
|||
g^=h<<8; b+=g; h+=a;
|
||||
h^=a>>9; c+=h; a+=b;
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
for _ in range(0u, 4) {
|
||||
mix!();
|
||||
}
|
||||
|
||||
if use_rsl {
|
||||
macro_rules! memloop (
|
||||
macro_rules! memloop {
|
||||
($arr:expr) => {{
|
||||
for i in range_step(0, RAND_SIZE as uint, 8) {
|
||||
a+=$arr[i ]; b+=$arr[i+1];
|
||||
|
@ -101,7 +101,7 @@ impl IsaacRng {
|
|||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
|
@ -129,41 +129,42 @@ impl IsaacRng {
|
|||
|
||||
static MIDPOINT: uint = (RAND_SIZE / 2) as uint;
|
||||
|
||||
macro_rules! ind (($x:expr) => {
|
||||
self.mem[(($x >> 2) as uint & ((RAND_SIZE - 1) as uint))]
|
||||
});
|
||||
macro_rules! ind {
|
||||
($x:expr) => ( self.mem[(($x >> 2) as uint & ((RAND_SIZE - 1) as uint))] )
|
||||
}
|
||||
|
||||
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
|
||||
for &(mr_offset, m2_offset) in r.iter() {
|
||||
|
||||
macro_rules! rngstepp(
|
||||
macro_rules! rngstepp {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = $j;
|
||||
let mix = a << $shift as uint;
|
||||
let base = $j;
|
||||
let mix = a << $shift as uint;
|
||||
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
);
|
||||
macro_rules! rngstepn(
|
||||
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! rngstepn {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = $j;
|
||||
let mix = a >> $shift as uint;
|
||||
let base = $j;
|
||||
let mix = a >> $shift as uint;
|
||||
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
);
|
||||
b = ind!(y >> RAND_SIZE_LEN as uint) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
}
|
||||
|
||||
for i in range_step(0u, MIDPOINT, 4) {
|
||||
rngstepp!(i + 0, 13);
|
||||
|
@ -301,15 +302,15 @@ impl Isaac64Rng {
|
|||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||
/// randomly).
|
||||
fn init(&mut self, use_rsl: bool) {
|
||||
macro_rules! init (
|
||||
macro_rules! init {
|
||||
($var:ident) => (
|
||||
let mut $var = 0x9e3779b97f4a7c13;
|
||||
)
|
||||
);
|
||||
}
|
||||
init!(a); init!(b); init!(c); init!(d);
|
||||
init!(e); init!(f); init!(g); init!(h);
|
||||
|
||||
macro_rules! mix(
|
||||
macro_rules! mix {
|
||||
() => {{
|
||||
a-=e; f^=h>>9; h+=a;
|
||||
b-=f; g^=a<<9; a+=b;
|
||||
|
@ -320,14 +321,14 @@ impl Isaac64Rng {
|
|||
g-=c; d^=f>>17; f+=g;
|
||||
h-=d; e^=g<<14; g+=h;
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
for _ in range(0u, 4) {
|
||||
mix!();
|
||||
}
|
||||
|
||||
if use_rsl {
|
||||
macro_rules! memloop (
|
||||
macro_rules! memloop {
|
||||
($arr:expr) => {{
|
||||
for i in range(0, RAND_SIZE_64 / 8).map(|i| i * 8) {
|
||||
a+=$arr[i ]; b+=$arr[i+1];
|
||||
|
@ -341,7 +342,7 @@ impl Isaac64Rng {
|
|||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
);
|
||||
}
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
|
@ -366,49 +367,51 @@ impl Isaac64Rng {
|
|||
let mut b = self.b + self.c;
|
||||
const MIDPOINT: uint = RAND_SIZE_64 / 2;
|
||||
const MP_VEC: [(uint, uint); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
|
||||
macro_rules! ind (
|
||||
macro_rules! ind {
|
||||
($x:expr) => {
|
||||
*self.mem.get_unchecked(($x as uint >> 3) & (RAND_SIZE_64 - 1))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for &(mr_offset, m2_offset) in MP_VEC.iter() {
|
||||
for base in range(0, MIDPOINT / 4).map(|i| i * 4) {
|
||||
|
||||
macro_rules! rngstepp(
|
||||
macro_rules! rngstepp {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = base + $j;
|
||||
let mix = a ^ (a << $shift as uint);
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
let base = base + $j;
|
||||
let mix = a ^ (a << $shift as uint);
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
|
||||
unsafe {
|
||||
let x = *self.mem.get_unchecked(base + mr_offset);
|
||||
a = mix + *self.mem.get_unchecked(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
*self.mem.get_unchecked_mut(base + mr_offset) = y;
|
||||
unsafe {
|
||||
let x = *self.mem.get_unchecked(base + mr_offset);
|
||||
a = mix + *self.mem.get_unchecked(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
*self.mem.get_unchecked_mut(base + mr_offset) = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||
}
|
||||
}}
|
||||
);
|
||||
macro_rules! rngstepn(
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! rngstepn {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = base + $j;
|
||||
let mix = a ^ (a >> $shift as uint);
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
let base = base + $j;
|
||||
let mix = a ^ (a >> $shift as uint);
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
|
||||
unsafe {
|
||||
let x = *self.mem.get_unchecked(base + mr_offset);
|
||||
a = mix + *self.mem.get_unchecked(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
*self.mem.get_unchecked_mut(base + mr_offset) = y;
|
||||
unsafe {
|
||||
let x = *self.mem.get_unchecked(base + mr_offset);
|
||||
a = mix + *self.mem.get_unchecked(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
*self.mem.get_unchecked_mut(base + mr_offset) = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||
}
|
||||
}}
|
||||
);
|
||||
rngstepp!(0u, 21);
|
||||
rngstepn!(1u, 5);
|
||||
rngstepp!(2u, 12);
|
||||
|
|
|
@ -29,11 +29,29 @@
|
|||
#![no_std]
|
||||
#![experimental]
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[phase(plugin, link)]
|
||||
extern crate core;
|
||||
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate std;
|
||||
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
||||
#[cfg(not(stage0))]
|
||||
#[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::*;
|
||||
|
||||
|
|
|
@ -30,7 +30,14 @@
|
|||
|
||||
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;
|
||||
|
||||
pub use self::EbmlEncoderTag::*;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
|
||||
#![allow(unknown_features)]
|
||||
#![feature(macro_rules, phase, slicing_syntax, globs)]
|
||||
#![feature(macro_rules, slicing_syntax, globs)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(associated_types)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
@ -40,8 +40,22 @@ extern crate rustc_back;
|
|||
extern crate serialize;
|
||||
extern crate rbml;
|
||||
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
|
||||
|
||||
|
|
|
@ -167,21 +167,27 @@ impl LintStore {
|
|||
}
|
||||
|
||||
pub fn register_builtin(&mut self, sess: Option<&Session>) {
|
||||
macro_rules! add_builtin ( ( $sess:ident, $($name:ident),*, ) => (
|
||||
{$(
|
||||
self.register_pass($sess, false, box builtin::$name as LintPassObject);
|
||||
)*}
|
||||
));
|
||||
macro_rules! add_builtin {
|
||||
($sess:ident, $($name:ident),*,) => (
|
||||
{$(
|
||||
self.register_pass($sess, false, box builtin::$name as LintPassObject);
|
||||
)*}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! add_builtin_with_new ( ( $sess:ident, $($name:ident),*, ) => (
|
||||
{$(
|
||||
self.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
|
||||
)*}
|
||||
));
|
||||
macro_rules! add_builtin_with_new {
|
||||
($sess:ident, $($name:ident),*,) => (
|
||||
{$(
|
||||
self.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
|
||||
)*}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => (
|
||||
self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
|
||||
));
|
||||
macro_rules! add_lint_group {
|
||||
($sess:ident, $name:expr, $($lint:ident),*) => (
|
||||
self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
|
||||
)
|
||||
}
|
||||
|
||||
add_builtin!(sess,
|
||||
HardwiredLints,
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
||||
//! in `context.rs`.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
pub use self::Level::*;
|
||||
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_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_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_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::search_paths::PathKind;
|
||||
use metadata::cstore;
|
||||
use metadata::cstore::{CStore, CrateSource};
|
||||
use metadata::cstore::{CStore, CrateSource, MetadataBlob};
|
||||
use metadata::decoder;
|
||||
use metadata::loader;
|
||||
use metadata::loader::CratePaths;
|
||||
use plugin::load::PluginMetadata;
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
@ -29,43 +28,27 @@ use syntax::ast;
|
|||
use syntax::abi;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::codemap::{Span};
|
||||
use syntax::codemap::{Span, mk_sp};
|
||||
use syntax::diagnostic::SpanHandler;
|
||||
use syntax::parse;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token;
|
||||
use syntax::visit;
|
||||
use util::fs;
|
||||
use log;
|
||||
|
||||
struct Env<'a> {
|
||||
pub struct CrateReader<'a> {
|
||||
sess: &'a Session,
|
||||
next_crate_num: ast::CrateNum,
|
||||
}
|
||||
|
||||
// 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(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> {
|
||||
impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
|
||||
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);
|
||||
}
|
||||
fn visit_item(&mut self, a: &ast::Item) {
|
||||
visit_item(self, a);
|
||||
self.process_item(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 {
|
||||
i.attrs.iter().all(|attr| {
|
||||
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 => ()
|
||||
}
|
||||
!attr::contains_name(i.attrs[], "no_link")
|
||||
}
|
||||
|
||||
struct CrateInfo {
|
||||
|
@ -150,32 +99,6 @@ struct CrateInfo {
|
|||
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>) {
|
||||
let err = |&: s: &str| {
|
||||
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,
|
||||
span: Option<Span>,
|
||||
name: String,
|
||||
|
@ -304,172 +148,341 @@ fn register_native_lib(sess: &Session,
|
|||
sess.cstore.add_used_library(name, kind);
|
||||
}
|
||||
|
||||
fn existing_match(e: &Env, name: &str,
|
||||
hash: Option<&Svh>) -> Option<ast::CrateNum> {
|
||||
let mut ret = None;
|
||||
e.sess.cstore.iter_crate_data(|cnum, data| {
|
||||
if data.name != name { return }
|
||||
pub struct PluginMetadata<'a> {
|
||||
sess: &'a Session,
|
||||
metadata: PMDSource,
|
||||
dylib: Option<Path>,
|
||||
info: CrateInfo,
|
||||
vi_span: Span,
|
||||
target_only: bool,
|
||||
}
|
||||
|
||||
match hash {
|
||||
Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
|
||||
Some(..) => return,
|
||||
None => {}
|
||||
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;
|
||||
}
|
||||
|
||||
// When the hash is None we're dealing with a top-level dependency in
|
||||
// which case we may have a specification on the command line for this
|
||||
// library. Even though an upstream library may have loaded something of
|
||||
// the same name, we have to make sure it was loaded from the exact same
|
||||
// location as well.
|
||||
//
|
||||
// We're also sure to compare *paths*, not actual byte slices. The
|
||||
// `source` stores paths which are normalized which may be different
|
||||
// from the strings on the command line.
|
||||
let source = e.sess.cstore.get_used_crate_source(cnum).unwrap();
|
||||
match e.sess.opts.externs.get(name) {
|
||||
Some(locs) => {
|
||||
let found = locs.iter().any(|l| {
|
||||
let l = fs::realpath(&Path::new(l[])).ok();
|
||||
l == source.dylib || l == source.rlib
|
||||
});
|
||||
if found {
|
||||
ret = Some(cnum);
|
||||
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 => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => ret = Some(cnum),
|
||||
_ => { }
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn register_crate<'a>(e: &mut Env,
|
||||
root: &Option<CratePaths>,
|
||||
ident: &str,
|
||||
name: &str,
|
||||
span: Span,
|
||||
lib: loader::Library)
|
||||
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
||||
cstore::CrateSource) {
|
||||
// Claim this crate number and cache it
|
||||
let cnum = e.next_crate_num;
|
||||
e.next_crate_num += 1;
|
||||
|
||||
// Stash paths for top-most crate locally if necessary.
|
||||
let crate_paths = if root.is_none() {
|
||||
Some(CratePaths {
|
||||
ident: ident.to_string(),
|
||||
dylib: lib.dylib.clone(),
|
||||
rlib: lib.rlib.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Maintain a reference to the top most crate.
|
||||
let root = if root.is_some() { root } else { &crate_paths };
|
||||
|
||||
let cnum_map = resolve_crate_deps(e, root, lib.metadata.as_slice(), span);
|
||||
|
||||
let loader::Library{ dylib, rlib, metadata } = lib;
|
||||
|
||||
let cmeta = Rc::new( cstore::crate_metadata {
|
||||
name: name.to_string(),
|
||||
data: metadata,
|
||||
cnum_map: cnum_map,
|
||||
cnum: cnum,
|
||||
span: span,
|
||||
});
|
||||
|
||||
let source = cstore::CrateSource {
|
||||
dylib: dylib,
|
||||
rlib: rlib,
|
||||
cnum: cnum,
|
||||
};
|
||||
|
||||
e.sess.cstore.set_crate_data(cnum, cmeta.clone());
|
||||
e.sess.cstore.add_used_crate_source(source.clone());
|
||||
(cnum, cmeta, source)
|
||||
}
|
||||
|
||||
fn resolve_crate(e: &mut Env,
|
||||
root: &Option<CratePaths>,
|
||||
ident: &str,
|
||||
name: &str,
|
||||
hash: Option<&Svh>,
|
||||
span: Span,
|
||||
kind: PathKind)
|
||||
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
||||
cstore::CrateSource) {
|
||||
match existing_match(e, name, hash) {
|
||||
None => {
|
||||
let mut load_ctxt = loader::Context {
|
||||
sess: e.sess,
|
||||
span: span,
|
||||
ident: ident,
|
||||
crate_name: name,
|
||||
hash: hash.map(|a| &*a),
|
||||
filesearch: e.sess.target_filesearch(kind),
|
||||
triple: e.sess.opts.target_triple[],
|
||||
root: root,
|
||||
rejected_via_hash: vec!(),
|
||||
rejected_via_triple: vec!(),
|
||||
should_match_name: true,
|
||||
};
|
||||
let library = load_ctxt.load_library_crate();
|
||||
register_crate(e, root, ident, name, span, library)
|
||||
}
|
||||
Some(cnum) => (cnum,
|
||||
e.sess.cstore.get_crate_data(cnum),
|
||||
e.sess.cstore.get_used_crate_source(cnum).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
// Go through the crate metadata and load any crates that it references
|
||||
fn resolve_crate_deps(e: &mut Env,
|
||||
root: &Option<CratePaths>,
|
||||
cdata: &[u8], span : Span)
|
||||
-> cstore::cnum_map {
|
||||
debug!("resolving deps of external crate");
|
||||
// The map from crate numbers in the crate we're resolving to local crate
|
||||
// numbers
|
||||
decoder::get_crate_deps(cdata).iter().map(|dep| {
|
||||
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
||||
let (local_cnum, _, _) = resolve_crate(e, root,
|
||||
dep.name[],
|
||||
dep.name[],
|
||||
Some(&dep.hash),
|
||||
span,
|
||||
PathKind::Dependency);
|
||||
(dep.cnum, local_cnum)
|
||||
}).collect()
|
||||
}
|
||||
fn existing_match(&self, name: &str,
|
||||
hash: Option<&Svh>) -> Option<ast::CrateNum> {
|
||||
let mut ret = None;
|
||||
self.sess.cstore.iter_crate_data(|cnum, data| {
|
||||
if data.name != name { return }
|
||||
|
||||
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(),
|
||||
match hash {
|
||||
Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
|
||||
Some(..) => return,
|
||||
None => {}
|
||||
}
|
||||
|
||||
// When the hash is None we're dealing with a top-level dependency in
|
||||
// which case we may have a specification on the command line for this
|
||||
// library. Even though an upstream library may have loaded something of
|
||||
// the same name, we have to make sure it was loaded from the exact same
|
||||
// location as well.
|
||||
//
|
||||
// We're also sure to compare *paths*, not actual byte slices. The
|
||||
// `source` stores paths which are normalized which may be different
|
||||
// from the strings on the command line.
|
||||
let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
|
||||
match self.sess.opts.externs.get(name) {
|
||||
Some(locs) => {
|
||||
let found = locs.iter().any(|l| {
|
||||
let l = fs::realpath(&Path::new(l[])).ok();
|
||||
l == source.dylib || l == source.rlib
|
||||
});
|
||||
if found {
|
||||
ret = Some(cnum);
|
||||
}
|
||||
}
|
||||
None => ret = Some(cnum),
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn register_crate(&mut self,
|
||||
root: &Option<CratePaths>,
|
||||
ident: &str,
|
||||
name: &str,
|
||||
span: Span,
|
||||
lib: loader::Library)
|
||||
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
||||
cstore::CrateSource) {
|
||||
// Claim this crate number and cache it
|
||||
let cnum = self.next_crate_num;
|
||||
self.next_crate_num += 1;
|
||||
|
||||
// Stash paths for top-most crate locally if necessary.
|
||||
let crate_paths = if root.is_none() {
|
||||
Some(CratePaths {
|
||||
ident: ident.to_string(),
|
||||
dylib: lib.dylib.clone(),
|
||||
rlib: lib.rlib.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Maintain a reference to the top most crate.
|
||||
let root = if root.is_some() { root } else { &crate_paths };
|
||||
|
||||
let cnum_map = self.resolve_crate_deps(root, lib.metadata.as_slice(), span);
|
||||
|
||||
let loader::Library{ dylib, rlib, metadata } = lib;
|
||||
|
||||
let cmeta = Rc::new( cstore::crate_metadata {
|
||||
name: name.to_string(),
|
||||
data: metadata,
|
||||
cnum_map: cnum_map,
|
||||
cnum: cnum,
|
||||
span: span,
|
||||
});
|
||||
|
||||
let source = cstore::CrateSource {
|
||||
dylib: dylib,
|
||||
rlib: rlib,
|
||||
cnum: cnum,
|
||||
};
|
||||
|
||||
self.sess.cstore.set_crate_data(cnum, cmeta.clone());
|
||||
self.sess.cstore.add_used_crate_source(source.clone());
|
||||
(cnum, cmeta, source)
|
||||
}
|
||||
|
||||
fn resolve_crate(&mut self,
|
||||
root: &Option<CratePaths>,
|
||||
ident: &str,
|
||||
name: &str,
|
||||
hash: Option<&Svh>,
|
||||
span: Span,
|
||||
kind: PathKind)
|
||||
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
||||
cstore::CrateSource) {
|
||||
match self.existing_match(name, hash) {
|
||||
None => {
|
||||
let mut load_ctxt = loader::Context {
|
||||
sess: self.sess,
|
||||
span: span,
|
||||
ident: ident,
|
||||
crate_name: name,
|
||||
hash: hash.map(|a| &*a),
|
||||
filesearch: self.sess.target_filesearch(kind),
|
||||
triple: self.sess.opts.target_triple[],
|
||||
root: root,
|
||||
rejected_via_hash: vec!(),
|
||||
rejected_via_triple: vec!(),
|
||||
should_match_name: true,
|
||||
};
|
||||
let library = load_ctxt.load_library_crate();
|
||||
self.register_crate(root, ident, name, span, library)
|
||||
}
|
||||
Some(cnum) => (cnum,
|
||||
self.sess.cstore.get_crate_data(cnum),
|
||||
self.sess.cstore.get_used_crate_source(cnum).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_plugin_metadata(&mut self,
|
||||
krate: &ast::ViewItem) -> PluginMetadata {
|
||||
let info = extract_crate_info(&self.env, krate).unwrap();
|
||||
let target_triple = self.env.sess.opts.target_triple[];
|
||||
// Go through the crate metadata and load any crates that it references
|
||||
fn resolve_crate_deps(&mut self,
|
||||
root: &Option<CratePaths>,
|
||||
cdata: &[u8], span : Span)
|
||||
-> cstore::cnum_map {
|
||||
debug!("resolving deps of external crate");
|
||||
// The map from crate numbers in the crate we're resolving to local crate
|
||||
// numbers
|
||||
decoder::get_crate_deps(cdata).iter().map(|dep| {
|
||||
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
||||
let (local_cnum, _, _) = self.resolve_crate(root,
|
||||
dep.name[],
|
||||
dep.name[],
|
||||
Some(&dep.hash),
|
||||
span,
|
||||
PathKind::Dependency);
|
||||
(dep.cnum, local_cnum)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
pub fn read_plugin_metadata<'b>(&'b mut self,
|
||||
vi: &'b ast::ViewItem) -> PluginMetadata<'b> {
|
||||
let info = self.extract_crate_info(vi).unwrap();
|
||||
let target_triple = self.sess.opts.target_triple[];
|
||||
let is_cross = target_triple != config::host_triple();
|
||||
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 {
|
||||
sess: self.env.sess,
|
||||
span: krate.span,
|
||||
ident: info.ident[],
|
||||
crate_name: info.name[],
|
||||
sess: self.sess,
|
||||
span: vi.span,
|
||||
ident: ident[],
|
||||
crate_name: name[],
|
||||
hash: None,
|
||||
filesearch: self.env.sess.host_filesearch(PathKind::Crate),
|
||||
filesearch: self.sess.host_filesearch(PathKind::Crate),
|
||||
triple: config::host_triple(),
|
||||
root: &None,
|
||||
rejected_via_hash: vec!(),
|
||||
|
@ -479,49 +492,106 @@ impl<'a> PluginMetadataReader<'a> {
|
|||
let library = match load_ctxt.maybe_load_library_crate() {
|
||||
Some(l) => l,
|
||||
None if is_cross => {
|
||||
// try loading from target crates (only valid if there are
|
||||
// no syntax extensions)
|
||||
load_ctxt.triple = target_triple;
|
||||
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();
|
||||
}
|
||||
// Try loading from target crates. This will abort later if we try to
|
||||
// load a plugin registrar function,
|
||||
target_only = true;
|
||||
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!() },
|
||||
};
|
||||
let macros = decoder::get_exported_macros(library.metadata.as_slice());
|
||||
let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
|
||||
decoder::get_symbol(library.metadata.as_slice(), id)
|
||||
});
|
||||
if library.dylib.is_none() && registrar.is_some() {
|
||||
let message = format!("plugin crate `{}` only found in rlib format, \
|
||||
but must be available in dylib format",
|
||||
info.ident);
|
||||
self.env.sess.span_err(krate.span, message[]);
|
||||
// No need to abort because the loading code will just ignore this
|
||||
// empty dylib.
|
||||
}
|
||||
let pc = PluginMetadata {
|
||||
lib: library.dylib.clone(),
|
||||
macros: macros,
|
||||
registrar_symbol: registrar,
|
||||
|
||||
let dylib = library.dylib.clone();
|
||||
let register = should_link && self.existing_match(info.name[], None).is_none();
|
||||
let metadata = if register {
|
||||
// Register crate now to avoid double-reading metadata
|
||||
let (_, cmd, _) = self.register_crate(&None, info.ident[],
|
||||
info.name[], vi.span, library);
|
||||
PMDSource::Registered(cmd)
|
||||
} else {
|
||||
// Not registering the crate; just hold on to the metadata
|
||||
PMDSource::Owned(library.metadata)
|
||||
};
|
||||
if should_link && existing_match(&self.env, info.name[],
|
||||
None).is_none() {
|
||||
// register crate now to avoid double-reading metadata
|
||||
register_crate(&mut self.env, &None, info.ident[],
|
||||
info.name[], krate.span, library);
|
||||
|
||||
PluginMetadata {
|
||||
sess: self.sess,
|
||||
metadata: metadata,
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn get_exported_macros(data: &[u8]) -> Vec<String> {
|
||||
let macros = reader::get_doc(rbml::Doc::new(data),
|
||||
tag_exported_macros);
|
||||
let mut result = Vec::new();
|
||||
pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
|
||||
F: FnMut(ast::Name, Vec<ast::Attribute>, String) -> bool,
|
||||
{
|
||||
let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
|
||||
reader::tagged_docs(macros, tag_macro_def, |macro_doc| {
|
||||
result.push(macro_doc.as_str().to_string());
|
||||
true
|
||||
let name = item_name(intr, macro_doc);
|
||||
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)
|
||||
|
|
|
@ -42,6 +42,7 @@ use syntax::attr::AttrMetaMethods;
|
|||
use syntax::diagnostic::SpanHandler;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::visit::Visitor;
|
||||
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
|
||||
fn encode_macro_defs(ecx: &EncodeContext,
|
||||
krate: &ast::Crate,
|
||||
rbml_w: &mut Encoder) {
|
||||
rbml_w.start_tag(tag_exported_macros);
|
||||
for item in krate.exported_macros.iter() {
|
||||
encode_macro_def(ecx, rbml_w, &item.span);
|
||||
fn encode_macro_defs(rbml_w: &mut Encoder,
|
||||
krate: &ast::Crate) {
|
||||
rbml_w.start_tag(tag_macro_defs);
|
||||
for def in krate.exported_macros.iter() {
|
||||
rbml_w.start_tag(tag_macro_def);
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -2153,7 +2150,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
|
|||
|
||||
// Encode macro definitions
|
||||
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;
|
||||
|
||||
// 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")
|
||||
});
|
||||
|
||||
macro_rules! define_casts(
|
||||
macro_rules! define_casts {
|
||||
($val:ident, {
|
||||
$($ty_pat:pat => (
|
||||
$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())
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
eval_const_expr_partial(tcx, &**base)
|
||||
.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();
|
||||
|
||||
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! hash( ($e:expr) => { $e.hash(state) } );
|
||||
macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } }
|
||||
macro_rules! hash { ($e:expr) => { $e.hash(state) } }
|
||||
|
||||
let region = |&: state: &mut sip::SipState, r: Region| {
|
||||
match r {
|
||||
|
|
|
@ -8,47 +8,46 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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 metadata::creader::PluginMetadataReader;
|
||||
use metadata::creader::CrateReader;
|
||||
use plugin::registry::Registry;
|
||||
|
||||
use std::mem;
|
||||
use std::os;
|
||||
use std::dynamic_lib::DynamicLibrary;
|
||||
use std::collections::HashSet;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
use syntax::ptr::P;
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::ext::expand::ExportedMacros;
|
||||
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.
|
||||
pub type PluginRegistrarFun =
|
||||
fn(&mut Registry);
|
||||
|
||||
pub struct PluginRegistrar {
|
||||
pub fun: PluginRegistrarFun,
|
||||
pub args: P<ast::MetaItem>,
|
||||
}
|
||||
|
||||
/// Information about loaded plugins.
|
||||
pub struct Plugins {
|
||||
/// Source code of exported macros.
|
||||
pub macros: Vec<ExportedMacros>,
|
||||
/// Imported macros.
|
||||
pub macros: Vec<ast::MacroDef>,
|
||||
/// Registrars, as function pointers.
|
||||
pub registrars: Vec<PluginRegistrarFun>,
|
||||
pub registrars: Vec<PluginRegistrar>,
|
||||
}
|
||||
|
||||
struct PluginLoader<'a> {
|
||||
sess: &'a Session,
|
||||
reader: PluginMetadataReader<'a>,
|
||||
span_whitelist: HashSet<Span>,
|
||||
reader: CrateReader<'a>,
|
||||
plugins: Plugins,
|
||||
}
|
||||
|
||||
|
@ -56,7 +55,8 @@ impl<'a> PluginLoader<'a> {
|
|||
fn new(sess: &'a Session) -> PluginLoader<'a> {
|
||||
PluginLoader {
|
||||
sess: sess,
|
||||
reader: PluginMetadataReader::new(sess),
|
||||
reader: CrateReader::new(sess),
|
||||
span_whitelist: HashSet::new(),
|
||||
plugins: Plugins {
|
||||
macros: vec!(),
|
||||
registrars: vec!(),
|
||||
|
@ -69,6 +69,14 @@ impl<'a> PluginLoader<'a> {
|
|||
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
|
||||
addl_plugins: Option<Plugins>) -> Plugins {
|
||||
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);
|
||||
|
||||
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.
|
||||
impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
|
||||
fn visit_view_item(&mut self, vi: &ast::ViewItem) {
|
||||
// We're only interested in `extern crate`.
|
||||
match vi.node {
|
||||
ast::ViewItemExternCrate(name, _, _) => {
|
||||
let mut plugin_phase = false;
|
||||
ast::ViewItemExternCrate(..) => (),
|
||||
_ => 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;
|
||||
// Parse the attributes relating to macro / plugin loading.
|
||||
let mut plugin_attr = None;
|
||||
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");
|
||||
}
|
||||
if attr::contains_name(phases, "syntax") {
|
||||
plugin_phase = true;
|
||||
self.sess.span_warn(attr.span,
|
||||
"phase(syntax) is a deprecated synonym for phase(plugin)");
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
if !plugin_phase { return; }
|
||||
|
||||
let PluginMetadata { macros, lib, registrar_symbol } =
|
||||
self.reader.read_plugin_metadata(vi);
|
||||
|
||||
self.plugins.macros.push(ExportedMacros {
|
||||
crate_name: name,
|
||||
macros: macros,
|
||||
});
|
||||
|
||||
match (lib, registrar_symbol) {
|
||||
(Some(lib), Some(symbol))
|
||||
=> self.dylink_registrar(vi, lib, symbol),
|
||||
_ => (),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
let mut macros = vec![];
|
||||
let mut registrar = None;
|
||||
|
||||
let load_macros = match macro_selection.as_ref() {
|
||||
Some(sel) => sel.len() != 0 || reexport.len() != 0,
|
||||
None => true,
|
||||
};
|
||||
let load_registrar = plugin_attr.is_some();
|
||||
|
||||
if load_macros && !self.span_whitelist.contains(&vi.span) {
|
||||
self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \
|
||||
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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, _: &ast::Mac) {
|
||||
// bummer... can't see plugins inside macros.
|
||||
// do nothing.
|
||||
|
@ -132,7 +211,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
|
|||
|
||||
impl<'a> PluginLoader<'a> {
|
||||
// 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.
|
||||
let path = os::make_absolute(&path).unwrap();
|
||||
|
||||
|
@ -154,13 +236,12 @@ impl<'a> PluginLoader<'a> {
|
|||
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
|
||||
// since the library can make things that will live arbitrarily long
|
||||
// (e.g. an @-box cycle or a task).
|
||||
mem::forget(lib);
|
||||
|
||||
registrar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,14 +43,14 @@
|
|||
//! To use a plugin while compiling another crate:
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(phase)]
|
||||
//! #![feature(plugin)]
|
||||
//!
|
||||
//! #[phase(plugin)]
|
||||
//! #[plugin]
|
||||
//! extern crate myplugin;
|
||||
//! ```
|
||||
//!
|
||||
//! If you also need the plugin crate available at runtime, use
|
||||
//! `phase(plugin, link)`.
|
||||
//! If you don't need the plugin crate available at runtime, use
|
||||
//! `#[no_link]` as well.
|
||||
//!
|
||||
//! See [the compiler plugin guide](../../guide-plugin.html)
|
||||
//! for more examples.
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
//! Used by plugin crates to tell `rustc` about the plugins they provide.
|
||||
|
||||
use lint::{LintPassObject, LintId, Lint};
|
||||
use session::Session;
|
||||
|
||||
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::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ast;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -29,7 +31,14 @@ use std::collections::HashMap;
|
|||
/// This struct has public fields and other methods for use by `rustc`
|
||||
/// itself. They are not documented here, and plugin authors should
|
||||
/// 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)]
|
||||
pub krate_span: Span,
|
||||
|
||||
|
@ -43,10 +52,12 @@ pub struct Registry {
|
|||
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
impl<'a> Registry<'a> {
|
||||
#[doc(hidden)]
|
||||
pub fn new(krate: &ast::Crate) -> Registry {
|
||||
pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
|
||||
Registry {
|
||||
sess: sess,
|
||||
args_hidden: None,
|
||||
krate_span: krate.span,
|
||||
syntax_exts: 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.
|
||||
///
|
||||
/// 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)),
|
||||
Decorator(ext) => Decorator(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(old_orphan_check)]
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[phase(plugin, link)]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate syntax;
|
||||
extern crate serialize;
|
||||
|
||||
|
|
|
@ -346,12 +346,12 @@ impl Engine256State {
|
|||
|
||||
// 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.
|
||||
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];
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! sha2_round(
|
||||
macro_rules! sha2_round {
|
||||
($A:ident, $B:ident, $C:ident, $D:ident,
|
||||
$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);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
read_u32v_be(w.slice_mut(0, 16), data);
|
||||
|
||||
|
|
|
@ -327,11 +327,11 @@ mod svh_visitor {
|
|||
|
||||
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,
|
||||
// *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
|
||||
// surface artifacts (currently), such as the span
|
||||
// information, yielding a content-based hash.
|
||||
|
@ -341,7 +341,7 @@ mod svh_visitor {
|
|||
// trees might be faster. Implementing this is far
|
||||
// easier in short term.
|
||||
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);
|
||||
} else {
|
||||
|
@ -349,14 +349,14 @@ mod svh_visitor {
|
|||
// invocation at this stage except `macro_rules!`.
|
||||
panic!("reached macro somehow: {}",
|
||||
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 {
|
||||
match ¯o.node {
|
||||
fn macro_name(mac: &Mac) -> token::InternedString {
|
||||
match &mac.node {
|
||||
&MacInvocTT(ref path, ref _tts, ref _stx_ctxt) => {
|
||||
let s = path.segments[];
|
||||
assert_eq!(s.len(), 1);
|
||||
|
|
|
@ -239,7 +239,7 @@ impl Target {
|
|||
options: Default::default(),
|
||||
};
|
||||
|
||||
macro_rules! key (
|
||||
macro_rules! key {
|
||||
($key_name:ident) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.find(name[]).map(|o| o.as_string()
|
||||
|
@ -257,7 +257,7 @@ impl Target {
|
|||
)
|
||||
);
|
||||
} );
|
||||
);
|
||||
}
|
||||
|
||||
key!(cpu);
|
||||
key!(linker);
|
||||
|
@ -305,7 +305,7 @@ impl Target {
|
|||
}
|
||||
|
||||
// this would use a match if stringify! were allowed in pattern position
|
||||
macro_rules! load_specific (
|
||||
macro_rules! load_specific {
|
||||
( $($name:ident),+ ) => (
|
||||
{
|
||||
let target = target.replace("-", "_");
|
||||
|
@ -326,7 +326,7 @@ impl Target {
|
|||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
load_specific!(
|
||||
x86_64_unknown_linux_gnu,
|
||||
|
|
|
@ -39,15 +39,6 @@ use syntax::visit;
|
|||
use syntax::visit::{Visitor, FnKind};
|
||||
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 check_loans;
|
||||
|
|
|
@ -24,8 +24,21 @@
|
|||
#![feature(old_orphan_check)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[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;
|
||||
|
||||
// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
|
||||
// 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::search_paths::PathKind;
|
||||
use rustc::lint;
|
||||
use rustc::metadata::creader;
|
||||
use rustc::metadata::creader::CrateReader;
|
||||
use rustc::middle::{stability, ty, reachable};
|
||||
use rustc::middle::dependency_format;
|
||||
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
|
||||
// configuration variables e.g/ in
|
||||
//
|
||||
// #[macro_escape] #[cfg(foo)]
|
||||
// #[macro_use] #[cfg(foo)]
|
||||
// mod bar { macro_rules! baz!(() => {{}}) }
|
||||
//
|
||||
// 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", (), |_|
|
||||
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 {
|
||||
registry.register_macro("__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);
|
||||
}
|
||||
|
||||
for ®istrar in registrars.iter() {
|
||||
registrar(&mut registry);
|
||||
for registrar in registrars.into_iter() {
|
||||
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();
|
||||
|
||||
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", (), |_|
|
||||
middle::lang_items::collect_language_items(krate, &sess));
|
||||
|
|
|
@ -39,11 +39,25 @@ extern crate rustc_borrowck;
|
|||
extern crate rustc_resolve;
|
||||
extern crate rustc_trans;
|
||||
extern crate rustc_typeck;
|
||||
#[phase(plugin, link)] extern crate log;
|
||||
#[phase(plugin, link)] extern crate syntax;
|
||||
extern crate serialize;
|
||||
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;
|
||||
|
||||
use rustc_trans::back::link;
|
||||
|
|
|
@ -484,8 +484,8 @@ impl fold::Folder for ReplaceBodyWithLoop {
|
|||
|
||||
// in general the pretty printer processes unexpanded code, so
|
||||
// we override the default `fold_mac` method which panics.
|
||||
fn fold_mac(&mut self, _macro: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(_macro, self)
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(mac, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,21 @@
|
|||
#![feature(associated_types)]
|
||||
#![feature(old_orphan_check)]
|
||||
|
||||
#[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 rustc;
|
||||
|
||||
|
|
|
@ -37,11 +37,25 @@ extern crate graphviz;
|
|||
extern crate libc;
|
||||
extern crate rustc;
|
||||
extern crate rustc_back;
|
||||
#[phase(plugin, link)] extern crate log;
|
||||
#[phase(plugin, link)] extern crate syntax;
|
||||
extern crate serialize;
|
||||
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::metadata;
|
||||
pub use rustc::middle;
|
||||
|
|
|
@ -736,7 +736,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
|||
}
|
||||
|
||||
fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {
|
||||
macro_rules! ifn (
|
||||
macro_rules! ifn {
|
||||
($name:expr fn() -> $ret:expr) => (
|
||||
if *key == $name {
|
||||
let f = base::decl_cdecl_fn(
|
||||
|
@ -754,10 +754,10 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
|
|||
return Some(f);
|
||||
}
|
||||
)
|
||||
);
|
||||
macro_rules! mk_struct (
|
||||
}
|
||||
macro_rules! mk_struct {
|
||||
($($field_ty:expr),*) => (Type::struct_(ccx, &[$($field_ty),*], false))
|
||||
);
|
||||
}
|
||||
|
||||
let i8p = Type::i8p(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
|
||||
// fallbacks in libc or libm and such. Currently, all of these intrinsics
|
||||
// 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) => (
|
||||
if unsafe { llvm::LLVMVersionMinor() >= 4 } {
|
||||
// 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);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
compatible_ifn!("llvm.copysign.f32", copysignf(t_f32, t_f32) -> t_f32);
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
macro_rules! unpack_datum {
|
||||
($bcx: ident, $inp: expr) => (
|
||||
{
|
||||
|
|
|
@ -16,8 +16,11 @@ pub use self::base::trans_crate;
|
|||
pub use self::context::CrateContext;
|
||||
pub use self::common::gensym_name;
|
||||
|
||||
mod doc;
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
mod macros;
|
||||
|
||||
mod doc;
|
||||
mod inline;
|
||||
mod monomorphize;
|
||||
mod controlflow;
|
||||
|
|
|
@ -77,8 +77,21 @@ This API is completely unstable and subject to change.
|
|||
#![feature(unboxed_closures)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[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 arena;
|
||||
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::DocComment(..) => "doccomment",
|
||||
token::Underscore | token::Eof | token::Interpolated(..) |
|
||||
|
|
|
@ -32,7 +32,14 @@ extern crate rustc_driver;
|
|||
extern crate serialize;
|
||||
extern crate syntax;
|
||||
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
|
||||
|
||||
|
@ -49,11 +56,13 @@ use rustc::session::search_paths::SearchPaths;
|
|||
// reexported from `clean` so it can be easily updated with the mod itself
|
||||
pub use clean::SCHEMA_VERSION;
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
pub mod externalfiles;
|
||||
|
||||
pub mod clean;
|
||||
pub mod core;
|
||||
pub mod doctree;
|
||||
#[macro_escape]
|
||||
pub mod externalfiles;
|
||||
pub mod fold;
|
||||
pub mod html {
|
||||
pub mod highlight;
|
||||
|
|
|
@ -73,7 +73,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
None);
|
||||
// attach the crate's exported macros to the top-level module:
|
||||
self.module.macros = krate.exported_macros.iter()
|
||||
.map(|it| self.visit_macro(&**it)).collect();
|
||||
.map(|def| self.visit_macro(def)).collect();
|
||||
self.module.is_crate = true;
|
||||
}
|
||||
|
||||
|
@ -363,13 +363,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
id: item.id,
|
||||
attrs: item.attrs.clone(),
|
||||
name: item.ident,
|
||||
whence: item.span,
|
||||
stab: self.stability(item.id),
|
||||
id: def.id,
|
||||
attrs: def.attrs.clone(),
|
||||
name: def.ident,
|
||||
whence: def.span,
|
||||
stab: self.stability(def.id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,14 @@ Core encoding and decoding interfaces.
|
|||
#[cfg(test)]
|
||||
extern crate test;
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[phase(plugin, link)]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate unicode;
|
||||
|
||||
extern crate collections;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![experimental]
|
||||
#![macro_escape]
|
||||
|
||||
//! A typesafe bitmask flag generator.
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@ use hash::{Hash, Hasher, RandomSipHasher};
|
|||
use iter::{Iterator, IteratorExt, FromIterator, Map, Chain, Extend};
|
||||
use ops::{BitOr, BitAnd, BitXor, Sub};
|
||||
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};
|
||||
|
||||
|
|
|
@ -18,11 +18,14 @@ use iter::{IteratorExt, ExactSizeIterator};
|
|||
use ops::Drop;
|
||||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
use result::Result::{Ok, Err};
|
||||
use result::Result::Ok;
|
||||
use slice::{SliceExt};
|
||||
use slice;
|
||||
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
|
||||
///
|
||||
/// It can be excessively inefficient to work directly with a `Reader`. For
|
||||
|
|
|
@ -282,10 +282,13 @@ pub mod net;
|
|||
pub mod pipe;
|
||||
pub mod process;
|
||||
pub mod stdio;
|
||||
pub mod test;
|
||||
pub mod timer;
|
||||
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
|
||||
// libuv recommends 64k buffers to maximize throughput
|
||||
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
//! Various utility functions useful for writing I/O tests
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use libc;
|
||||
|
|
|
@ -117,13 +117,36 @@
|
|||
|
||||
#![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 unicode;
|
||||
extern crate core;
|
||||
extern crate "collections" as core_collections;
|
||||
extern crate "rand" as core_rand;
|
||||
extern crate libc;
|
||||
|
||||
// Make std testable by not duplicating lang items. See #2912
|
||||
|
@ -167,7 +190,18 @@ pub use unicode::char;
|
|||
|
||||
/* 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;
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
pub mod bitflags;
|
||||
|
||||
mod rtdeps;
|
||||
|
@ -179,9 +213,20 @@ pub mod prelude;
|
|||
|
||||
/* Primitive types */
|
||||
|
||||
#[path = "num/float_macros.rs"] mod float_macros;
|
||||
#[path = "num/int_macros.rs"] mod int_macros;
|
||||
#[path = "num/uint_macros.rs"] mod uint_macros;
|
||||
#[path = "num/float_macros.rs"]
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[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/i8.rs"] pub mod i8;
|
||||
|
@ -210,6 +255,10 @@ pub mod num;
|
|||
|
||||
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 ffi;
|
||||
pub mod fmt;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
//! library.
|
||||
|
||||
#![experimental]
|
||||
#![macro_escape]
|
||||
|
||||
/// The entry point for panic of Rust tasks.
|
||||
///
|
||||
|
@ -246,34 +245,6 @@ 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]
|
||||
|
@ -306,23 +277,15 @@ macro_rules! println {
|
|||
#[macro_export]
|
||||
macro_rules! try {
|
||||
($expr:expr) => ({
|
||||
use $crate::result::Result::{Ok, Err};
|
||||
|
||||
match $expr {
|
||||
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.
|
||||
///
|
||||
/// 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),+
|
||||
) => ({
|
||||
use std::sync::mpsc::Select;
|
||||
use $crate::sync::mpsc::Select;
|
||||
let sel = Select::new();
|
||||
$( let mut $rx = sel.handle(&$rx); )+
|
||||
unsafe {
|
||||
|
|
|
@ -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.
|
||||
|
||||
#![experimental]
|
||||
#![macro_escape]
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! assert_approx_eq {
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![experimental]
|
||||
#![macro_escape]
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! int_module { ($T:ty) => (
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![experimental]
|
||||
#![macro_escape]
|
||||
#![doc(hidden)]
|
||||
#![allow(unsigned_negation)]
|
||||
|
||||
|
|
|
@ -535,7 +535,7 @@ mod tests {
|
|||
t!(b"foo/\xFFbar", filename_display, "\u{FFFD}bar");
|
||||
t!(b"/", filename_display, "");
|
||||
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
($path:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -550,7 +550,7 @@ mod tests {
|
|||
assert!(mo.as_slice() == $exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!("foo", "foo");
|
||||
t!(b"foo\x80", "foo\u{FFFD}");
|
||||
|
@ -562,7 +562,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_display() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
($path:expr, $exp:expr, $expf:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -572,7 +572,7 @@ mod tests {
|
|||
assert!(f == $expf);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(b"foo", "foo", "foo");
|
||||
t!(b"foo/bar", "foo/bar", "bar");
|
||||
|
@ -585,7 +585,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_components() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $op:ident, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -606,7 +606,7 @@ mod tests {
|
|||
assert!(path.$op() == $exp);
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
t!(v: b"a/b/c", filename, Some(b"c"));
|
||||
t!(v: b"a/b/c\xFF", filename, Some(b"c\xFF"));
|
||||
|
@ -669,7 +669,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_push() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $join:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -680,7 +680,7 @@ mod tests {
|
|||
assert!(p1 == p2.join(join));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a/b/c", "..");
|
||||
t!(s: "/a/b/c", "d");
|
||||
|
@ -690,7 +690,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_push_path() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||
{
|
||||
let mut p = Path::new($path);
|
||||
|
@ -699,7 +699,7 @@ mod tests {
|
|||
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");
|
||||
|
@ -711,7 +711,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_push_many() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||
{
|
||||
let mut p = Path::new($path);
|
||||
|
@ -726,7 +726,7 @@ mod tests {
|
|||
assert!(p.as_vec() == $exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
|
||||
t!(s: "a/b/c", ["d", "/e"], "/e");
|
||||
|
@ -739,7 +739,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_pop() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $left:expr, $right:expr) => (
|
||||
{
|
||||
let mut p = Path::new($path);
|
||||
|
@ -756,7 +756,7 @@ mod tests {
|
|||
assert!(result == $right);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(b: b"a/b/c", b"a/b", true);
|
||||
t!(b: b"a", b".", true);
|
||||
|
@ -795,7 +795,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_join_path() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -804,7 +804,7 @@ mod tests {
|
|||
assert!(res.as_str() == Some($exp));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a/b/c", "..", "a/b");
|
||||
t!(s: "/a/b/c", "d", "/a/b/c/d");
|
||||
|
@ -816,7 +816,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_join_many() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -831,7 +831,7 @@ mod tests {
|
|||
assert!(res.as_vec() == $exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
|
||||
t!(s: "a/b/c", ["..", "d"], "a/b/d");
|
||||
|
@ -894,7 +894,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_setters() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -915,7 +915,7 @@ mod tests {
|
|||
assert!(p1 == p2.$with(arg));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(v: b"a/b/c", set_filename, with_filename, b"d");
|
||||
t!(v: b"/", set_filename, with_filename, b"foo");
|
||||
|
@ -938,7 +938,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_getters() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -969,7 +969,7 @@ mod tests {
|
|||
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/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None);
|
||||
|
@ -1008,7 +1008,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_is_absolute() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $abs:expr, $rel:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1016,7 +1016,7 @@ mod tests {
|
|||
assert_eq!(path.is_relative(), $rel);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
t!(s: "a/b/c", false, true);
|
||||
t!(s: "/a/b/c", true, false);
|
||||
t!(s: "a", false, true);
|
||||
|
@ -1029,7 +1029,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_is_ancestor_of() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $dest:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1037,7 +1037,7 @@ mod tests {
|
|||
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", true);
|
||||
|
@ -1063,7 +1063,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_ends_with_path() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $child:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1078,7 +1078,7 @@ mod tests {
|
|||
assert_eq!(path.ends_with_path(&child), $exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a/b/c", "c", true);
|
||||
t!(s: "a/b/c", "d", false);
|
||||
|
@ -1102,7 +1102,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_path_relative_from() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $other:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1111,7 +1111,7 @@ mod tests {
|
|||
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/d", Some("../c"));
|
||||
|
@ -1147,7 +1147,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_components_iter() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1173,7 +1173,7 @@ mod tests {
|
|||
assert_eq!(comps, exp)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(b: b"a/b/c", [b"a", b"b", b"c"]);
|
||||
t!(b: b"/\xFF/a/\x80", [b"\xFF", b"a", b"\x80"]);
|
||||
|
@ -1193,7 +1193,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_str_components() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(b: $arg:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($arg);
|
||||
|
@ -1205,7 +1205,7 @@ mod tests {
|
|||
assert_eq!(comps, exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(b: b"a/b/c", [Some("a"), Some("b"), Some("c")]);
|
||||
t!(b: b"/\xFF/a/\x80", [None, Some("a"), None]);
|
||||
|
|
|
@ -1127,7 +1127,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_parse_prefix() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
($path:expr, $exp:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -1137,7 +1137,7 @@ mod tests {
|
|||
"parse_prefix(\"{}\"): expected {}, found {}", path, exp, res);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5)));
|
||||
t!("\\\\", None);
|
||||
|
@ -1326,7 +1326,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_display() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
($path:expr, $exp:expr, $expf:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1336,7 +1336,7 @@ mod tests {
|
|||
assert_eq!(f, $expf);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!("foo", "foo", "foo");
|
||||
t!("foo\\bar", "foo\\bar", "bar");
|
||||
|
@ -1345,7 +1345,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_components() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $op:ident, $exp:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -1368,7 +1368,7 @@ mod tests {
|
|||
assert!(path.$op() == $exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(v: b"a\\b\\c", filename, Some(b"c"));
|
||||
t!(s: "a\\b\\c", filename_str, "c");
|
||||
|
@ -1468,7 +1468,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_push() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $join:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -1479,7 +1479,7 @@ mod tests {
|
|||
assert!(p1 == p2.join(join));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", "..");
|
||||
t!(s: "\\a\\b\\c", "d");
|
||||
|
@ -1503,7 +1503,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_push_path() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||
{
|
||||
let mut p = Path::new($path);
|
||||
|
@ -1512,7 +1512,7 @@ mod tests {
|
|||
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");
|
||||
|
@ -1555,7 +1555,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_push_many() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $push:expr, $exp:expr) => (
|
||||
{
|
||||
let mut p = Path::new($path);
|
||||
|
@ -1570,7 +1570,7 @@ mod tests {
|
|||
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"], "\\e");
|
||||
|
@ -1584,7 +1584,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_pop() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $left:expr, $right:expr) => (
|
||||
{
|
||||
let pstr = $path;
|
||||
|
@ -1605,7 +1605,7 @@ mod tests {
|
|||
assert!(result == $right);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", "a\\b", true);
|
||||
t!(s: "a", ".", true);
|
||||
|
@ -1673,7 +1673,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_join_path() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1682,7 +1682,7 @@ mod tests {
|
|||
assert_eq!(res.as_str(), Some($exp));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", "..", "a\\b");
|
||||
t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
|
||||
|
@ -1696,7 +1696,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_join_many() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $join:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1711,7 +1711,7 @@ mod tests {
|
|||
assert_eq!(res.as_vec(), $exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
|
||||
t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d");
|
||||
|
@ -1724,7 +1724,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_with_helpers() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $op:ident, $arg:expr, $res:expr) => (
|
||||
{
|
||||
let pstr = $path;
|
||||
|
@ -1737,7 +1737,7 @@ mod tests {
|
|||
pstr, stringify!($op), arg, exp, res.as_str().unwrap());
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d");
|
||||
t!(s: ".", with_filename, "foo", "foo");
|
||||
|
@ -1809,7 +1809,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_setters() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -1830,7 +1830,7 @@ mod tests {
|
|||
assert!(p1 == p2.$with(arg));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(v: b"a\\b\\c", set_filename, with_filename, b"d");
|
||||
t!(v: b"\\", set_filename, with_filename, b"foo");
|
||||
|
@ -1854,7 +1854,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_getters() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
|
@ -1885,7 +1885,7 @@ mod tests {
|
|||
assert!(path.extension() == $ext);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1920,7 +1920,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_is_absolute() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1939,7 +1939,7 @@ mod tests {
|
|||
path.as_str().unwrap(), rel, b);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
t!("a\\b\\c", false, false, false, true);
|
||||
t!("\\a\\b\\c", false, true, false, false);
|
||||
t!("a", false, false, false, true);
|
||||
|
@ -1960,7 +1960,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_is_ancestor_of() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $dest:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -1972,7 +1972,7 @@ mod tests {
|
|||
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", true);
|
||||
|
@ -2063,7 +2063,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_ends_with_path() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $child:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -2071,7 +2071,7 @@ mod tests {
|
|||
assert_eq!(path.ends_with_path(&child), $exp);
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", "c", true);
|
||||
t!(s: "a\\b\\c", "d", false);
|
||||
|
@ -2095,7 +2095,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_path_relative_from() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $other:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -2108,7 +2108,7 @@ mod tests {
|
|||
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\\d", Some("..\\c"));
|
||||
|
@ -2229,7 +2229,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_str_components() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -2243,7 +2243,7 @@ mod tests {
|
|||
assert_eq!(comps, exp);
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: b"a\\b\\c", ["a", "b", "c"]);
|
||||
t!(s: "a\\b\\c", ["a", "b", "c"]);
|
||||
|
@ -2287,7 +2287,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_components_iter() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
(s: $path:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -2299,7 +2299,7 @@ mod tests {
|
|||
assert_eq!(comps, exp);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
t!(s: "a\\b\\c", [b"a", b"b", b"c"]);
|
||||
t!(s: ".", [b"."]);
|
||||
|
@ -2308,7 +2308,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_make_non_verbatim() {
|
||||
macro_rules! t(
|
||||
macro_rules! t {
|
||||
($path:expr, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
|
@ -2317,7 +2317,7 @@ mod tests {
|
|||
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"));
|
||||
|
|
|
@ -23,11 +23,14 @@ mod imp {
|
|||
use path::Path;
|
||||
use rand::Rng;
|
||||
use rand::reader::ReaderRng;
|
||||
use result::Result::{Ok, Err};
|
||||
use result::Result::Ok;
|
||||
use slice::SliceExt;
|
||||
use mem;
|
||||
use os::errno;
|
||||
|
||||
// NOTE: for old macros; remove after the next snapshot
|
||||
#[cfg(stage0)] use result::Result::Err;
|
||||
|
||||
#[cfg(all(target_os = "linux",
|
||||
any(target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
//! These macros call functions which are only accessible in the `rt` module, so
|
||||
//! they aren't defined anywhere outside of the `rt` module.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
macro_rules! rterrln {
|
||||
($fmt:expr $($arg:tt)*) => ( {
|
||||
::rt::util::dumb_print(format_args!(concat!($fmt, "\n") $($arg)*))
|
||||
|
|
|
@ -39,6 +39,8 @@ pub use alloc::heap;
|
|||
pub mod backtrace;
|
||||
|
||||
// Internals
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
mod macros;
|
||||
|
||||
// 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
|
||||
//! `Cell` or `RefCell` types.
|
||||
|
||||
#![macro_escape]
|
||||
#![stable]
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use cell::UnsafeCell;
|
||||
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
pub mod scoped;
|
||||
|
||||
// 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 \
|
||||
stabilizing its interface"]
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@ use ops::{Add, Sub, Mul, Div, Neg, FnOnce};
|
|||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
use num::Int;
|
||||
use result::Result;
|
||||
use result::Result::{Ok, Err};
|
||||
use result::Result::Ok;
|
||||
|
||||
// NOTE: for old macros; remove after the next snapshot
|
||||
#[cfg(stage0)] use result::Result::Err;
|
||||
|
||||
/// The number of nanoseconds in a microsecond.
|
||||
const NANOS_PER_MICRO: i32 = 1000;
|
||||
|
|
|
@ -476,7 +476,7 @@ pub struct Crate {
|
|||
pub attrs: Vec<Attribute>,
|
||||
pub config: CrateConfig,
|
||||
pub span: Span,
|
||||
pub exported_macros: Vec<P<Item>>
|
||||
pub exported_macros: Vec<MacroDef>,
|
||||
}
|
||||
|
||||
pub type MetaItem = Spanned<MetaItem_>;
|
||||
|
@ -884,6 +884,7 @@ impl TokenTree {
|
|||
match *self {
|
||||
TtToken(_, token::DocComment(_)) => 2,
|
||||
TtToken(_, token::SubstNt(..)) => 2,
|
||||
TtToken(_, token::SpecialVarNt(..)) => 2,
|
||||
TtToken(_, token::MatchNt(..)) => 3,
|
||||
TtDelimited(_, ref delimed) => {
|
||||
delimed.tts.len() + 2
|
||||
|
@ -925,6 +926,12 @@ impl TokenTree {
|
|||
TtToken(sp, token::Ident(name, name_st))];
|
||||
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)), _) => {
|
||||
let v = [TtToken(sp, token::SubstNt(name, name_st)),
|
||||
TtToken(sp, token::Colon),
|
||||
|
@ -1689,6 +1696,21 @@ pub enum InlinedItem {
|
|||
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)]
|
||||
mod test {
|
||||
use serialize::json;
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! register_diagnostic {
|
||||
($code:tt, $description:tt) => (__register_diagnostic! { $code, $description });
|
||||
|
|
|
@ -16,6 +16,7 @@ use codemap;
|
|||
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
|
||||
use ext;
|
||||
use ext::expand;
|
||||
use ext::tt::macro_rules;
|
||||
use parse;
|
||||
use parse::parser;
|
||||
use parse::token;
|
||||
|
@ -28,19 +29,6 @@ use fold::Folder;
|
|||
use std::collections::HashMap;
|
||||
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 {
|
||||
fn expand(&self,
|
||||
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
|
||||
/// just into the compiler's internal macro table, for `make_def`).
|
||||
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.
|
||||
fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
|
||||
None
|
||||
|
@ -328,13 +309,8 @@ pub enum SyntaxExtension {
|
|||
///
|
||||
IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
||||
|
||||
/// An ident macro that has two properties:
|
||||
/// - it adds a macro definition to the environment, and
|
||||
/// - the definition it adds doesn't introduce any new
|
||||
/// identifiers.
|
||||
///
|
||||
/// `macro_rules!` is a LetSyntaxTT
|
||||
LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
|
||||
/// Represents `macro_rules!` itself.
|
||||
MacroRulesTT,
|
||||
}
|
||||
|
||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||
|
@ -364,8 +340,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
|
|||
}
|
||||
|
||||
let mut syntax_expanders = SyntaxEnv::new();
|
||||
syntax_expanders.insert(intern("macro_rules"),
|
||||
LetSyntaxTT(box ext::tt::macro_rules::add_new_extension, None));
|
||||
syntax_expanders.insert(intern("macro_rules"), MacroRulesTT);
|
||||
syntax_expanders.insert(intern("fmt"),
|
||||
builtin_normal_expander(
|
||||
ext::fmt::expand_syntax_ext));
|
||||
|
@ -475,7 +450,7 @@ pub struct ExtCtxt<'a> {
|
|||
|
||||
pub mod_path: Vec<ast::Ident> ,
|
||||
pub trace_mac: bool,
|
||||
pub exported_macros: Vec<P<ast::Item>>,
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
|
||||
pub syntax_env: SyntaxEnv,
|
||||
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.
|
||||
///
|
||||
/// `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)
|
||||
}
|
||||
|
||||
macro_rules! md (
|
||||
macro_rules! md {
|
||||
($name:expr, $f:ident) => { {
|
||||
let inline = cx.meta_word(span, InternedString::new("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 {
|
||||
span: span,
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn expand_deriving_ord<F>(cx: &mut ExtCtxt,
|
|||
push: F) where
|
||||
F: FnOnce(P<Item>),
|
||||
{
|
||||
macro_rules! md (
|
||||
macro_rules! md {
|
||||
($name:expr, $op:expr, $equal:expr) => { {
|
||||
let inline = cx.meta_word(span, InternedString::new("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 ret_ty = Literal(Path::new_(vec!["std", "option", "Option"],
|
||||
|
|
|
@ -71,9 +71,11 @@ pub fn expand_meta_derive(cx: &mut ExtCtxt,
|
|||
MetaNameValue(ref tname, _) |
|
||||
MetaList(ref tname, _) |
|
||||
MetaWord(ref tname) => {
|
||||
macro_rules! expand(($func:path) => ($func(cx, titem.span,
|
||||
&**titem, item,
|
||||
|i| push.call_mut((i,)))));
|
||||
macro_rules! expand {
|
||||
($func:path) => ($func(cx, titem.span, &**titem, item,
|
||||
|i| push.call_mut((i,))))
|
||||
}
|
||||
|
||||
match tname.get() {
|
||||
"Clone" => expand!(clone::expand_deriving_clone),
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// <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.
|
||||
use self::Either::*;
|
||||
|
||||
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
||||
use ast::{Local, Ident, MacInvocTT};
|
||||
|
@ -33,11 +32,6 @@ use util::small_vector::SmallVector;
|
|||
use visit;
|
||||
use visit::Visitor;
|
||||
|
||||
enum Either<L,R> {
|
||||
Left(L),
|
||||
Right(R)
|
||||
}
|
||||
|
||||
pub fn expand_type(t: P<ast::Ty>,
|
||||
fld: &mut MacroExpander,
|
||||
impl_ty: Option<P<ast::Ty>>)
|
||||
|
@ -445,9 +439,9 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
|
|||
if valid_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,
|
||||
macro_escape,
|
||||
macro_use,
|
||||
noop_fold_item(it, fld));
|
||||
if valid_ident {
|
||||
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" ?
|
||||
fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
|
||||
attr::contains_name(attrs, "macro_escape")
|
||||
// does this attribute list contain "macro_use" ?
|
||||
fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
|
||||
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
|
||||
// logic as for expression-position macro invocations.
|
||||
pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
||||
-> SmallVector<P<ast::Item>> {
|
||||
pub fn expand_item_mac(it: P<ast::Item>,
|
||||
fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
|
||||
let (extname, path_span, tts) = match it.node {
|
||||
ItemMac(codemap::Spanned {
|
||||
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 fm = fresh_mark();
|
||||
let def_or_items = {
|
||||
let mut expanded = match fld.cx.syntax_env.find(&extname.name) {
|
||||
let items = {
|
||||
let expanded = match fld.cx.syntax_env.find(&extname.name) {
|
||||
None => {
|
||||
fld.cx.span_err(path_span,
|
||||
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);
|
||||
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 {
|
||||
fld.cx.span_err(path_span,
|
||||
format!("macro {}! expects an ident argument",
|
||||
extnamestr.get())[]);
|
||||
format!("macro_rules! expects an ident argument")[]);
|
||||
return SmallVector::zero();
|
||||
}
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
|
@ -612,11 +624,26 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
|||
callee: NameAndSpan {
|
||||
name: extnamestr.get().to_string(),
|
||||
format: MacroBang,
|
||||
span: span
|
||||
span: None,
|
||||
}
|
||||
});
|
||||
// DON'T mark before expansion:
|
||||
expander.expand(fld.cx, it.span, it.ident, tts)
|
||||
// DON'T mark before expansion.
|
||||
|
||||
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,
|
||||
|
@ -627,31 +654,17 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
|||
}
|
||||
};
|
||||
|
||||
match expanded.make_def() {
|
||||
Some(def) => Left(def),
|
||||
None => Right(expanded.make_items())
|
||||
}
|
||||
expanded.make_items()
|
||||
};
|
||||
|
||||
let items = match def_or_items {
|
||||
Left(MacroDef { name, ext }) => {
|
||||
// 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)) => {
|
||||
let items = match items {
|
||||
Some(items) => {
|
||||
items.into_iter()
|
||||
.map(|i| mark_item(i, fm))
|
||||
.flat_map(|i| fld.fold_item(i).into_iter())
|
||||
.collect()
|
||||
}
|
||||
Right(None) => {
|
||||
None => {
|
||||
fld.cx.span_err(path_span,
|
||||
format!("non-item macro in item position: {}",
|
||||
extnamestr.get())[]);
|
||||
|
@ -664,9 +677,6 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
|
|||
}
|
||||
|
||||
/// 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>> {
|
||||
let (mac, style) = match s.node {
|
||||
StmtMac(mac, style) => (mac, style),
|
||||
|
@ -976,8 +986,8 @@ impl<'a> Folder for IdentRenamer<'a> {
|
|||
ctxt: mtwt::apply_renames(self.renames, id.ctxt),
|
||||
}
|
||||
}
|
||||
fn fold_mac(&mut self, macro: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(macro, self)
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(mac, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1013,8 +1023,8 @@ impl<'a> Folder for PatIdentRenamer<'a> {
|
|||
_ => unreachable!()
|
||||
})
|
||||
}
|
||||
fn fold_mac(&mut self, macro: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(macro, self)
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||
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,
|
||||
cfg: ExpansionConfig,
|
||||
// these are the macros being imported to this crate:
|
||||
imported_macros: Vec<ExportedMacros>,
|
||||
imported_macros: Vec<ast::MacroDef>,
|
||||
user_exts: Vec<NamedSyntaxExtension>,
|
||||
c: Crate) -> Crate {
|
||||
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
|
||||
let mut expander = MacroExpander::new(&mut cx);
|
||||
|
||||
for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
|
||||
let name = format!("<{} macros>", token::get_ident(crate_name));
|
||||
|
||||
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 def in imported_macros.into_iter() {
|
||||
expander.cx.insert_macro(def);
|
||||
}
|
||||
|
||||
for (name, extension) in user_exts.into_iter() {
|
||||
|
@ -1288,8 +1284,8 @@ struct MacroExterminator<'a>{
|
|||
}
|
||||
|
||||
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
|
||||
fn visit_mac(&mut self, macro: &ast::Mac) {
|
||||
self.sess.span_diagnostic.span_bug(macro.span,
|
||||
fn visit_mac(&mut self, mac: &ast::Mac) {
|
||||
self.sess.span_diagnostic.span_bug(mac.span,
|
||||
"macro exterminator: expected AST \
|
||||
with no macro invocations");
|
||||
}
|
||||
|
@ -1298,7 +1294,7 @@ impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
|
|||
|
||||
#[cfg(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 ast;
|
||||
use ast::{Attribute_, AttrOuter, MetaWord, Name};
|
||||
|
@ -1395,9 +1391,9 @@ mod test {
|
|||
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 () {
|
||||
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();
|
||||
let sess = parse::new_parse_sess();
|
||||
let crate_ast = parse::parse_crate_from_source_str(
|
||||
|
@ -1407,16 +1403,6 @@ mod test {
|
|||
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
|
||||
fn make_dummy_attr(s: &str) -> ast::Attribute {
|
||||
Spanned {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
use ast::{Ident, TtDelimited, TtSequence, TtToken};
|
||||
use ast;
|
||||
use codemap::{Span, DUMMY_SP};
|
||||
use ext::base::{ExtCtxt, MacResult, MacroDef};
|
||||
use ext::base::{ExtCtxt, MacResult, SyntaxExtension};
|
||||
use ext::base::{NormalTT, TTMacroExpander};
|
||||
use ext::tt::macro_parser::{Success, Error, Failure};
|
||||
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
|
||||
/// silently drop anything. `allow_semi` is so that "optional"
|
||||
/// semicolons at the end of normal expressions aren't complained
|
||||
/// about e.g. the semicolon in `macro_rules! kapow( () => {
|
||||
/// panic!(); } )` doesn't get picked up by .parse_expr(), but it's
|
||||
/// about e.g. the semicolon in `macro_rules! kapow { () => {
|
||||
/// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
|
||||
/// allowed to be there.
|
||||
fn ensure_complete_parse(&self, allow_semi: bool) {
|
||||
let mut parser = self.parser.borrow_mut();
|
||||
|
@ -110,6 +110,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
|||
|
||||
struct MacroRulesMacroExpander {
|
||||
name: Ident,
|
||||
imported_from: Option<Ident>,
|
||||
lhses: Vec<Rc<NamedMatch>>,
|
||||
rhses: Vec<Rc<NamedMatch>>,
|
||||
}
|
||||
|
@ -123,25 +124,18 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
|||
generic_extension(cx,
|
||||
sp,
|
||||
self.name,
|
||||
self.imported_from,
|
||||
arg,
|
||||
self.lhses[],
|
||||
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
|
||||
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||
sp: Span,
|
||||
name: Ident,
|
||||
imported_from: Option<Ident>,
|
||||
arg: &[ast::TokenTree],
|
||||
lhses: &[Rc<NamedMatch>],
|
||||
rhses: &[Rc<NamedMatch>])
|
||||
|
@ -165,6 +159,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||
};
|
||||
// `None` is because we're not interpolating
|
||||
let mut arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||
None,
|
||||
None,
|
||||
arg.iter()
|
||||
.map(|x| (*x).clone())
|
||||
|
@ -186,6 +181,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||
Some(named_matches),
|
||||
imported_from,
|
||||
rhs);
|
||||
let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
|
||||
// Let the context choose how to interpret the result.
|
||||
|
@ -212,14 +208,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||
//
|
||||
// Holy self-referential!
|
||||
|
||||
/// This procedure performs the expansion of the
|
||||
/// macro_rules! macro. It parses the RHS and adds
|
||||
/// an extension to the current context.
|
||||
pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||
sp: Span,
|
||||
name: Ident,
|
||||
arg: Vec<ast::TokenTree> )
|
||||
-> Box<MacResult+'cx> {
|
||||
/// Converts a `macro_rules!` invocation into a syntax extension.
|
||||
pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
|
||||
def: &ast::MacroDef) -> SyntaxExtension {
|
||||
|
||||
let lhs_nm = gensym_ident("lhs");
|
||||
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):
|
||||
let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||
None,
|
||||
arg.clone());
|
||||
None,
|
||||
def.body.clone());
|
||||
let argument_map = parse_or_else(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
arg_reader,
|
||||
|
@ -265,24 +257,20 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
|
|||
// Extract the arguments:
|
||||
let lhses = match *argument_map[lhs_nm] {
|
||||
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] {
|
||||
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 {
|
||||
name: name,
|
||||
name: def.ident,
|
||||
imported_from: def.imported_from,
|
||||
lhses: lhses,
|
||||
rhses: rhses,
|
||||
};
|
||||
|
||||
box MacroRulesDefiner {
|
||||
def: Some(MacroDef {
|
||||
name: token::get_ident(name).to_string(),
|
||||
ext: NormalTT(exp, Some(sp))
|
||||
})
|
||||
} as Box<MacResult+'cx>
|
||||
NormalTT(exp, Some(def.span))
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use codemap::{Span, DUMMY_SP};
|
|||
use diagnostic::SpanHandler;
|
||||
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
||||
use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt};
|
||||
use parse::token::{Token, NtIdent};
|
||||
use parse::token::{Token, NtIdent, SpecialMacroVar};
|
||||
use parse::token;
|
||||
use parse::lexer::TokenAndSpan;
|
||||
|
||||
|
@ -39,6 +39,10 @@ pub struct TtReader<'a> {
|
|||
stack: Vec<TtFrame>,
|
||||
/* for MBE-style macro transcription */
|
||||
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_len: Vec<uint>,
|
||||
/* cached: */
|
||||
|
@ -53,6 +57,7 @@ pub struct TtReader<'a> {
|
|||
/// should) be none.
|
||||
pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
|
||||
interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
|
||||
imported_from: Option<Ident>,
|
||||
src: Vec<ast::TokenTree> )
|
||||
-> TtReader<'a> {
|
||||
let mut r = TtReader {
|
||||
|
@ -71,6 +76,8 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
|
|||
None => HashMap::new(),
|
||||
Some(x) => x,
|
||||
},
|
||||
imported_from: imported_from,
|
||||
crate_name_next: None,
|
||||
repeat_idx: Vec::new(),
|
||||
repeat_len: Vec::new(),
|
||||
desugar_doc_comments: false,
|
||||
|
@ -162,6 +169,14 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
|
|||
sp: r.cur_span.clone(),
|
||||
};
|
||||
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() {
|
||||
None => {
|
||||
assert_eq!(ret_val.tok, token::Eof);
|
||||
|
@ -307,6 +322,18 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
|
|||
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) => {
|
||||
r.cur_span = sp;
|
||||
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
|
||||
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||
("globs", Accepted),
|
||||
("macro_rules", Active),
|
||||
("macro_rules", Accepted),
|
||||
("struct_variant", Accepted),
|
||||
("asm", Active),
|
||||
("managed_boxes", Removed),
|
||||
("non_ascii_idents", Active),
|
||||
("thread_local", Active),
|
||||
("link_args", Active),
|
||||
("phase", Active),
|
||||
("phase", Active), // NOTE(stage0): switch to Removed after next snapshot
|
||||
("plugin_registrar", Active),
|
||||
("log_syntax", Active),
|
||||
("trace_macros", Active),
|
||||
|
@ -74,6 +74,8 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
|||
("if_let", Accepted),
|
||||
("while_let", Accepted),
|
||||
|
||||
("plugin", Active),
|
||||
|
||||
// A temporary feature gate used to enable parser extensions needed
|
||||
// to bootstrap fix for #5723.
|
||||
("issue_5723_bootstrap", Accepted),
|
||||
|
@ -161,32 +163,11 @@ struct MacroVisitor<'a> {
|
|||
}
|
||||
|
||||
impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
|
||||
fn visit_view_item(&mut self, i: &ast::ViewItem) {
|
||||
match i.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;
|
||||
fn visit_mac(&mut self, mac: &ast::Mac) {
|
||||
let ast::MacInvocTT(ref path, _, _) = mac.node;
|
||||
let id = path.segments.last().unwrap().identifier;
|
||||
|
||||
if id == token::str_to_ident("macro_rules") {
|
||||
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") {
|
||||
if id == token::str_to_ident("asm") {
|
||||
self.context.gate_feature("asm", path.span, "inline assembly is not \
|
||||
stable enough for use and is subject to change");
|
||||
}
|
||||
|
@ -233,10 +214,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
|
|||
ast::ViewItemUse(..) => {}
|
||||
ast::ViewItemExternCrate(..) => {
|
||||
for attr in i.attrs.iter() {
|
||||
if attr.name().get() == "phase"{
|
||||
self.gate_feature("phase", attr.span,
|
||||
"compile time crate loading is \
|
||||
experimental and possibly buggy");
|
||||
if attr.check_name("plugin") {
|
||||
self.gate_feature("plugin", attr.span,
|
||||
"compiler plugins are experimental \
|
||||
and possibly buggy");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,13 +194,13 @@ pub trait Folder : Sized {
|
|||
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");
|
||||
// NB: see note about macros above.
|
||||
// if you really want a folder that
|
||||
// works on macros, use this
|
||||
// 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 {
|
||||
|
@ -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 {
|
||||
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)
|
||||
};
|
||||
|
||||
for def in exported_macros.iter_mut() {
|
||||
def.id = folder.new_id(def.id);
|
||||
}
|
||||
|
||||
Crate {
|
||||
module: module,
|
||||
attrs: attrs,
|
||||
|
@ -1472,8 +1476,8 @@ mod test {
|
|||
fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
|
||||
token::str_to_ident("zz")
|
||||
}
|
||||
fn fold_mac(&mut self, macro: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(macro, self)
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(mac, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,18 @@
|
|||
|
||||
extern crate arena;
|
||||
extern crate fmt_macros;
|
||||
#[phase(plugin, link)] extern crate log;
|
||||
extern crate serialize;
|
||||
extern crate term;
|
||||
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
|
||||
|
||||
pub mod util {
|
||||
|
|
|
@ -24,8 +24,11 @@ use std::num::Int;
|
|||
use std::str;
|
||||
use std::iter;
|
||||
|
||||
pub mod lexer;
|
||||
#[cfg_attr(stage0, macro_escape)]
|
||||
#[cfg_attr(not(stage0), macro_use)]
|
||||
pub mod parser;
|
||||
|
||||
pub mod lexer;
|
||||
pub mod token;
|
||||
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`
|
||||
// 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,
|
||||
source: String,
|
||||
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,
|
||||
tts: Vec<ast::TokenTree>,
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -307,6 +312,8 @@ pub mod with_hygiene {
|
|||
|
||||
// Note: keep this in sync with `super::parse_tts_from_source_str` 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,
|
||||
source: String,
|
||||
cfg: ast::CrateConfig,
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
pub use self::PathParsingMode::*;
|
||||
use self::ItemOrViewItem::*;
|
||||
|
||||
|
@ -74,8 +72,8 @@ use parse::classify;
|
|||
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
|
||||
use parse::lexer::{Reader, TokenAndSpan};
|
||||
use parse::obsolete::*;
|
||||
use parse::token::{self, MatchNt, SubstNt, InternedString};
|
||||
use parse::token::{keywords, special_idents};
|
||||
use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
|
||||
use parse::token::{keywords, special_idents, SpecialMacroVar};
|
||||
use parse::{new_sub_parser_from_file, ParseSess};
|
||||
use print::pprust;
|
||||
use ptr::P;
|
||||
|
@ -2739,6 +2737,9 @@ impl<'a> Parser<'a> {
|
|||
op: repeat,
|
||||
num_captures: name_num
|
||||
}))
|
||||
} else if p.token.is_keyword_allow_following_colon(keywords::Crate) {
|
||||
p.bump();
|
||||
TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))
|
||||
} else {
|
||||
// A nonterminal that matches or not
|
||||
let namep = match p.token { token::Ident(_, p) => p, _ => token::Plain };
|
||||
|
@ -3881,13 +3882,13 @@ impl<'a> Parser<'a> {
|
|||
&mut stmts,
|
||||
&mut expr);
|
||||
}
|
||||
StmtMac(macro, MacStmtWithoutBraces) => {
|
||||
StmtMac(mac, MacStmtWithoutBraces) => {
|
||||
// statement macro without braces; might be an
|
||||
// expr depending on whether a semicolon follows
|
||||
match self.token {
|
||||
token::Semi => {
|
||||
stmts.push(P(Spanned {
|
||||
node: StmtMac(macro,
|
||||
node: StmtMac(mac,
|
||||
MacStmtWithSemicolon),
|
||||
span: span,
|
||||
}));
|
||||
|
@ -3896,10 +3897,16 @@ impl<'a> Parser<'a> {
|
|||
_ => {
|
||||
let e = self.mk_mac_expr(span.lo,
|
||||
span.hi,
|
||||
<<<<<<< HEAD
|
||||
macro.and_then(|m| m.node));
|
||||
let e = self.parse_dot_or_call_expr_with(e);
|
||||
let e = self.parse_more_binops(e, 0);
|
||||
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(
|
||||
e,
|
||||
ast::DUMMY_NODE_ID,
|
||||
|
@ -6026,6 +6033,10 @@ impl<'a> Parser<'a> {
|
|||
fn parse_view_path(&mut self) -> P<ViewPath> {
|
||||
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)) {
|
||||
// use {foo,bar}
|
||||
let idents = self.parse_unspanned_seq(
|
||||
|
|
|
@ -61,6 +61,21 @@ pub enum IdentStyle {
|
|||
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)]
|
||||
pub enum Lit {
|
||||
Byte(ast::Name),
|
||||
|
@ -143,6 +158,8 @@ pub enum Token {
|
|||
// In right-hand-sides of MBE macros:
|
||||
/// A syntactic variable that will be filled in by macro expansion.
|
||||
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
|
||||
// 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
|
||||
/// or reserved keyword.
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
@ -550,6 +574,7 @@ declare_special_idents_and_keywords! {
|
|||
(56, Abstract, "abstract");
|
||||
(57, Final, "final");
|
||||
(58, Override, "override");
|
||||
(59, Macro, "macro");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue