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:
Alex Crichton 2015-01-05 19:01:17 -08:00
commit 7975fd9cee
314 changed files with 3452 additions and 1605 deletions

View File

@ -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;

View File

@ -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

View File

@ -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() { }
```

View File

@ -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

View File

@ -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

View File

@ -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(..), _),

View File

@ -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

View File

@ -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;

View File

@ -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),*])
}

View File

@ -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>);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)]

View File

@ -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"))
}

View File

@ -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 {

View File

@ -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) => (

View File

@ -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) => (

View File

@ -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() { }
//! ```
//!

View File

@ -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,

View File

@ -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;

View File

@ -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 {
}
}
));
)}

View File

@ -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;

View File

@ -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);
}
}
));
)}

View File

@ -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;

View File

@ -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::*;

View File

@ -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::*;

View File

@ -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

View File

@ -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 } }

View File

@ -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]);

View File

@ -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)
}

View File

@ -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);

View File

@ -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::*;

View File

@ -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::*;

View File

@ -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)]

View File

@ -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

View File

@ -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,

View File

@ -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::*;

View File

@ -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;

View File

@ -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
}
}

View File

@ -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)

View File

@ -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.

View File

@ -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, {

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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.

View File

@ -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;
}
}));
}

View File

@ -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;

View File

@ -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);

View File

@ -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 &macro.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);

View File

@ -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,

View File

@ -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;

View File

@ -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.

View File

@ -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 &registrar 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));

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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) => (
{

View File

@ -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;

View File

@ -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;

View File

@ -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(..) |

View File

@ -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;

View File

@ -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),
}
}
}

View File

@ -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;

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![experimental]
#![macro_escape]
//! A typesafe bitmask flag generator.

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -10,8 +10,6 @@
//! Various utility functions useful for writing I/O tests
#![macro_escape]
use prelude::v1::*;
use libc;

View File

@ -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;

View File

@ -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 {

648
src/libstd/macros_stage0.rs Normal file
View File

@ -0,0 +1,648 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Standard library macros
//!
//! This modules contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.
#![experimental]
/// The entry point for panic of Rust tasks.
///
/// This macro is used to inject panic into a Rust task, causing the task to
/// unwind and panic entirely. Each task's panic can be reaped as the
/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be
/// the value which is transmitted.
///
/// The multi-argument form of this macro panics with a string and has the
/// `format!` syntax for building a string.
///
/// # Example
///
/// ```should_fail
/// # #![allow(unreachable_code)]
/// panic!();
/// panic!("this is a terrible mistake!");
/// panic!(4i); // panic with the value of 4 to be collected elsewhere
/// panic!("this is a {} {message}", "fancy", message = "message");
/// ```
#[macro_export]
macro_rules! panic {
() => ({
panic!("explicit panic")
});
($msg:expr) => ({
// static requires less code at runtime, more constant data
static _FILE_LINE: (&'static str, uint) = (file!(), line!());
::std::rt::begin_unwind($msg, &_FILE_LINE)
});
($fmt:expr, $($arg:tt)*) => ({
// The leading _'s are to avoid dead code warnings if this is
// used inside a dead function. Just `#[allow(dead_code)]` is
// insufficient, since the user may have
// `#[forbid(dead_code)]` and which cannot be overridden.
static _FILE_LINE: (&'static str, uint) = (file!(), line!());
::std::rt::begin_unwind_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE)
});
}
/// Ensure that a boolean expression is `true` at runtime.
///
/// This will invoke the `panic!` macro if the provided expression cannot be
/// evaluated to `true` at runtime.
///
/// # Example
///
/// ```
/// // the panic message for these assertions is the stringified value of the
/// // expression given.
/// assert!(true);
/// # fn some_computation() -> bool { true }
/// assert!(some_computation());
///
/// // assert with a custom message
/// # let x = true;
/// assert!(x, "x wasn't true!");
/// # let a = 3i; let b = 27i;
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[macro_export]
macro_rules! assert {
($cond:expr) => (
if !$cond {
panic!(concat!("assertion failed: ", stringify!($cond)))
}
);
($cond:expr, $($arg:expr),+) => (
if !$cond {
panic!($($arg),+)
}
);
}
/// Asserts that two expressions are equal to each other, testing equality in
/// both directions.
///
/// On panic, this macro will print the values of the expressions.
///
/// # Example
///
/// ```
/// let a = 3i;
/// let b = 1i + 2i;
/// assert_eq!(a, b);
/// ```
#[macro_export]
macro_rules! assert_eq {
($left:expr , $right:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
// check both directions of equality....
if !((*left_val == *right_val) &&
(*right_val == *left_val)) {
panic!("assertion failed: `(left == right) && (right == left)` \
(left: `{}`, right: `{}`)", *left_val, *right_val)
}
}
}
})
}
/// Ensure that a boolean expression is `true` at runtime.
///
/// This will invoke the `panic!` macro if the provided expression cannot be
/// evaluated to `true` at runtime.
///
/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing
/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for
/// checks that are too expensive to be present in a release build but may be
/// helpful during development.
///
/// # Example
///
/// ```
/// // the panic message for these assertions is the stringified value of the
/// // expression given.
/// debug_assert!(true);
/// # fn some_expensive_computation() -> bool { true }
/// debug_assert!(some_expensive_computation());
///
/// // assert with a custom message
/// # let x = true;
/// debug_assert!(x, "x wasn't true!");
/// # let a = 3i; let b = 27i;
/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[macro_export]
macro_rules! debug_assert {
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
}
/// Asserts that two expressions are equal to each other, testing equality in
/// both directions.
///
/// On panic, this macro will print the values of the expressions.
///
/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by
/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!`
/// useful for checks that are too expensive to be present in a release build
/// but may be helpful during development.
///
/// # Example
///
/// ```
/// let a = 3i;
/// let b = 1i + 2i;
/// debug_assert_eq!(a, b);
/// ```
#[macro_export]
macro_rules! debug_assert_eq {
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); })
}
/// A utility macro for indicating unreachable code.
///
/// This is useful any time that the compiler can't determine that some code is unreachable. For
/// example:
///
/// * Match arms with guard conditions.
/// * Loops that dynamically terminate.
/// * Iterators that dynamically terminate.
///
/// # Panics
///
/// This will always panic.
///
/// # Examples
///
/// Match arms:
///
/// ```rust
/// fn foo(x: Option<int>) {
/// match x {
/// Some(n) if n >= 0 => println!("Some(Non-negative)"),
/// Some(n) if n < 0 => println!("Some(Negative)"),
/// Some(_) => unreachable!(), // compile error if commented out
/// None => println!("None")
/// }
/// }
/// ```
///
/// Iterators:
///
/// ```rust
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
/// for i in std::iter::count(0_u32, 1) {
/// if 3*i < i { panic!("u32 overflow"); }
/// if x < 3*i { return i-1; }
/// }
/// unreachable!();
/// }
/// ```
#[macro_export]
macro_rules! unreachable {
() => ({
panic!("internal error: entered unreachable code")
});
($msg:expr) => ({
unreachable!("{}", $msg)
});
($fmt:expr, $($arg:tt)*) => ({
panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
});
}
/// A standardised placeholder for marking unfinished code. It panics with the
/// message `"not yet implemented"` when executed.
#[macro_export]
macro_rules! unimplemented {
() => (panic!("not yet implemented"))
}
/// Use the syntax described in `std::fmt` to create a value of type `String`.
/// See `std::fmt` for more information.
///
/// # Example
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10i, y = 30i);
/// ```
#[macro_export]
#[stable]
macro_rules! format {
($($arg:tt)*) => (::std::fmt::format(format_args!($($arg)*)))
}
/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
/// See `std::fmt` for more information.
///
/// # Example
///
/// ```
/// # #![allow(unused_must_use)]
///
/// let mut w = Vec::new();
/// write!(&mut w, "test");
/// write!(&mut w, "formatted {}", "arguments");
/// ```
#[macro_export]
#[stable]
macro_rules! write {
($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
}
/// Equivalent to the `write!` macro, except that a newline is appended after
/// the message is written.
#[macro_export]
#[stable]
macro_rules! writeln {
($dst:expr, $fmt:expr $($arg:tt)*) => (
write!($dst, concat!($fmt, "\n") $($arg)*)
)
}
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
#[macro_export]
#[stable]
macro_rules! print {
($($arg:tt)*) => (::std::io::stdio::print_args(format_args!($($arg)*)))
}
/// Macro for printing to a task's stdout handle.
///
/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
/// The syntax of this macro is the same as that used for `format!`. For more
/// information, see `std::fmt` and `std::io::stdio`.
///
/// # Example
///
/// ```
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
#[stable]
macro_rules! println {
($($arg:tt)*) => (::std::io::stdio::println_args(format_args!($($arg)*)))
}
/// Helper macro for unwrapping `Result` values while returning early with an
/// error if the value of the expression is `Err`. For more information, see
/// `std::io`.
#[macro_export]
macro_rules! try {
($expr:expr) => ({
match $expr {
Ok(val) => val,
Err(err) => return Err(::std::error::FromError::from_error(err))
}
})
}
/// Create a `std::vec::Vec` containing the arguments.
#[macro_export]
macro_rules! vec {
($($x:expr),*) => ({
let xs: ::std::boxed::Box<[_]> = box [$($x),*];
::std::slice::SliceExt::into_vec(xs)
});
($($x:expr,)*) => (vec![$($x),*])
}
/// A macro to select an event from a number of receivers.
///
/// This macro is used to wait for the first event to occur on a number of
/// receivers. It places no restrictions on the types of receivers given to
/// this macro, this can be viewed as a heterogeneous select.
///
/// # Example
///
/// ```
/// use std::thread::Thread;
/// use std::sync::mpsc::channel;
///
/// let (tx1, rx1) = channel();
/// let (tx2, rx2) = channel();
/// # fn long_running_task() {}
/// # fn calculate_the_answer() -> int { 42i }
///
/// Thread::spawn(move|| { long_running_task(); tx1.send(()) }).detach();
/// Thread::spawn(move|| { tx2.send(calculate_the_answer()) }).detach();
///
/// select! (
/// _ = rx1.recv() => println!("the long running task finished first"),
/// answer = rx2.recv() => {
/// println!("the answer was: {}", answer.unwrap());
/// }
/// )
/// ```
///
/// For more information about select, see the `std::sync::mpsc::Select` structure.
#[macro_export]
#[experimental]
macro_rules! select {
(
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
) => ({
use std::sync::mpsc::Select;
let sel = Select::new();
$( let mut $rx = sel.handle(&$rx); )+
unsafe {
$( $rx.add(); )+
}
let ret = sel.wait();
$( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
{ unreachable!() }
})
}
// When testing the standard library, we link to the liblog crate to get the
// logging macros. In doing so, the liblog crate was linked against the real
// version of libstd, and uses a different std::fmt module than the test crate
// uses. To get around this difference, we redefine the log!() macro here to be
// just a dumb version of what it should be.
#[cfg(test)]
macro_rules! log {
($lvl:expr, $($args:tt)*) => (
if log_enabled!($lvl) { println!($($args)*) }
)
}
/// Built-in macros to the compiler itself.
///
/// These macros do not have any corresponding definition with a `macro_rules!`
/// macro, but are documented here. Their implementations can be found hardcoded
/// into libsyntax itself.
#[cfg(dox)]
pub mod builtin {
/// The core macro for formatted string creation & output.
///
/// This macro produces a value of type `fmt::Arguments`. This value can be
/// passed to the functions in `std::fmt` for performing useful functions.
/// All other formatting macros (`format!`, `write!`, `println!`, etc) are
/// proxied through this one.
///
/// For more information, see the documentation in `std::fmt`.
///
/// # Example
///
/// ```rust
/// use std::fmt;
///
/// let s = fmt::format(format_args!("hello {}", "world"));
/// assert_eq!(s, format!("hello {}", "world"));
///
/// ```
#[macro_export]
macro_rules! format_args { ($fmt:expr $($args:tt)*) => ({
/* compiler built-in */
}) }
/// Inspect an environment variable at compile time.
///
/// This macro will expand to the value of the named environment variable at
/// compile time, yielding an expression of type `&'static str`.
///
/// If the environment variable is not defined, then a compilation error
/// will be emitted. To not emit a compile error, use the `option_env!`
/// macro instead.
///
/// # Example
///
/// ```rust
/// let path: &'static str = env!("PATH");
/// println!("the $PATH variable at the time of compiling was: {}", path);
/// ```
#[macro_export]
macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) }
/// Optionally inspect an environment variable at compile time.
///
/// If the named environment variable is present at compile time, this will
/// expand into an expression of type `Option<&'static str>` whose value is
/// `Some` of the value of the environment variable. If the environment
/// variable is not present, then this will expand to `None`.
///
/// A compile time error is never emitted when using this macro regardless
/// of whether the environment variable is present or not.
///
/// # Example
///
/// ```rust
/// let key: Option<&'static str> = option_env!("SECRET_KEY");
/// println!("the secret key might be: {}", key);
/// ```
#[macro_export]
macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) }
/// Concatenate literals into a static byte slice.
///
/// This macro takes any number of comma-separated literal expressions,
/// yielding an expression of type `&'static [u8]` which is the
/// concatenation (left to right) of all the literals in their byte format.
///
/// This extension currently only supports string literals, character
/// literals, and integers less than 256. The byte slice returned is the
/// utf8-encoding of strings and characters.
///
/// # Example
///
/// ```
/// let rust = bytes!("r", 'u', "st", 255);
/// assert_eq!(rust[1], b'u');
/// assert_eq!(rust[4], 255);
/// ```
#[macro_export]
macro_rules! bytes { ($($e:expr),*) => ({ /* compiler built-in */ }) }
/// Concatenate identifiers into one identifier.
///
/// This macro takes any number of comma-separated identifiers, and
/// concatenates them all into one, yielding an expression which is a new
/// identifier. Note that hygiene makes it such that this macro cannot
/// capture local variables, and macros are only allowed in item,
/// statement or expression position, meaning this macro may be difficult to
/// use in some situations.
///
/// # Example
///
/// ```
/// #![feature(concat_idents)]
///
/// # fn main() {
/// fn foobar() -> int { 23 }
///
/// let f = concat_idents!(foo, bar);
/// println!("{}", f());
/// # }
/// ```
#[macro_export]
macro_rules! concat_idents {
($($e:ident),*) => ({ /* compiler built-in */ })
}
/// Concatenates literals into a static string slice.
///
/// This macro takes any number of comma-separated literals, yielding an
/// expression of type `&'static str` which represents all of the literals
/// concatenated left-to-right.
///
/// Integer and floating point literals are stringified in order to be
/// concatenated.
///
/// # Example
///
/// ```
/// let s = concat!("test", 10i, 'b', true);
/// assert_eq!(s, "test10btrue");
/// ```
#[macro_export]
macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) }
/// A macro which expands to the line number on which it was invoked.
///
/// The expanded expression has type `uint`, and the returned line is not
/// the invocation of the `line!()` macro itself, but rather the first macro
/// invocation leading up to the invocation of the `line!()` macro.
///
/// # Example
///
/// ```
/// let current_line = line!();
/// println!("defined on line: {}", current_line);
/// ```
#[macro_export]
macro_rules! line { () => ({ /* compiler built-in */ }) }
/// A macro which expands to the column number on which it was invoked.
///
/// The expanded expression has type `uint`, and the returned column is not
/// the invocation of the `column!()` macro itself, but rather the first macro
/// invocation leading up to the invocation of the `column!()` macro.
///
/// # Example
///
/// ```
/// let current_col = column!();
/// println!("defined on column: {}", current_col);
/// ```
#[macro_export]
macro_rules! column { () => ({ /* compiler built-in */ }) }
/// A macro which expands to the file name from which it was invoked.
///
/// The expanded expression has type `&'static str`, and the returned file
/// is not the invocation of the `file!()` macro itself, but rather the
/// first macro invocation leading up to the invocation of the `file!()`
/// macro.
///
/// # Example
///
/// ```
/// let this_file = file!();
/// println!("defined in file: {}", this_file);
/// ```
#[macro_export]
macro_rules! file { () => ({ /* compiler built-in */ }) }
/// A macro which stringifies its argument.
///
/// This macro will yield an expression of type `&'static str` which is the
/// stringification of all the tokens passed to the macro. No restrictions
/// are placed on the syntax of the macro invocation itself.
///
/// # Example
///
/// ```
/// let one_plus_one = stringify!(1 + 1);
/// assert_eq!(one_plus_one, "1 + 1");
/// ```
#[macro_export]
macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
/// Includes a utf8-encoded file as a string.
///
/// This macro will yield an expression of type `&'static str` which is the
/// contents of the filename specified. The file is located relative to the
/// current file (similarly to how modules are found),
///
/// # Example
///
/// ```rust,ignore
/// let secret_key = include_str!("secret-key.ascii");
/// ```
#[macro_export]
macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) }
/// Includes a file as a byte slice.
///
/// This macro will yield an expression of type `&'static [u8]` which is
/// the contents of the filename specified. The file is located relative to
/// the current file (similarly to how modules are found),
///
/// # Example
///
/// ```rust,ignore
/// let secret_key = include_bytes!("secret-key.bin");
/// ```
#[macro_export]
macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) }
/// Deprecated alias for `include_bytes!()`.
#[macro_export]
macro_rules! include_bin { ($file:expr) => ({ /* compiler built-in */}) }
/// Expands to a string that represents the current module path.
///
/// The current module path can be thought of as the hierarchy of modules
/// leading back up to the crate root. The first component of the path
/// returned is the name of the crate currently being compiled.
///
/// # Example
///
/// ```rust
/// mod test {
/// pub fn foo() {
/// assert!(module_path!().ends_with("test"));
/// }
/// }
///
/// test::foo();
/// ```
#[macro_export]
macro_rules! module_path { () => ({ /* compiler built-in */ }) }
/// Boolean evaluation of configuration flags.
///
/// In addition to the `#[cfg]` attribute, this macro is provided to allow
/// boolean expression evaluation of configuration flags. This frequently
/// leads to less duplicated code.
///
/// The syntax given to this macro is the same syntax as the `cfg`
/// attribute.
///
/// # Example
///
/// ```rust
/// let my_directory = if cfg!(windows) {
/// "windows-specific-directory"
/// } else {
/// "unix-directory"
/// };
/// ```
#[macro_export]
macro_rules! cfg { ($cfg:tt) => ({ /* compiler built-in */ }) }
}

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![experimental]
#![macro_escape]
#![doc(hidden)]
macro_rules! assert_approx_eq {

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![experimental]
#![macro_escape]
#![doc(hidden)]
macro_rules! int_module { ($T:ty) => (

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![experimental]
#![macro_escape]
#![doc(hidden)]
#![allow(unsigned_negation)]

View File

@ -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]);

View File

@ -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"));

View File

@ -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",

View File

@ -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)*))

View File

@ -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

View File

@ -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?

View File

@ -38,7 +38,6 @@
//! });
//! ```
#![macro_escape]
#![unstable = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface"]

View File

@ -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;

View File

@ -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;

View File

@ -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 });

View File

@ -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:

View File

@ -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,

View File

@ -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"],

View File

@ -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),

View File

@ -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 {

View File

@ -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))
}

View File

@ -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;

View File

@ -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");
}
}
}

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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,

View File

@ -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(

View File

@ -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