diff options
| author | Steven Fackler <sfackler@gmail.com> | 2014-08-03 14:25:30 -0700 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2014-09-23 23:47:45 -0700 |
| commit | e520bb1b2f1667f17c3503af71273921c4fc9989 (patch) | |
| tree | 2b9b68d41ef081045271bdcfeea6fafbb6927f4d /src/libsyntax | |
| parent | c8bafe0466e6abb7342fc72fdf276d70ae83205b (diff) | |
| download | rust-e520bb1b2f1667f17c3503af71273921c4fc9989.tar.gz rust-e520bb1b2f1667f17c3503af71273921c4fc9989.zip | |
Add a cfg_attr syntax extension
This extends cfg-gating to attributes.
```rust
#[cfg_attr(<cfg pattern>, <attr>)]
```
will expand to
```rust
#[<attr>]
```
if the `<cfg pattern>` matches the current cfg environment, and nothing
if it does not. The grammar for the cfg pattern has a simple
recursive structure:
* `value` and `key = "value"` are cfg patterns,
* `not(<cfg pattern>)` is a cfg pattern and matches if `<cfg pattern>`
does not.
* `all(<cfg pattern>, ...)` is a cfg pattern and matches if all of the
`<cfg pattern>`s do.
* `any(<cfg pattern>, ...)` is a cfg pattern and matches if any of the
`<cfg pattern>`s do.
Examples:
```rust
// only derive Show for assert_eq! in tests
#[cfg_attr(test, deriving(Show))]
struct Foo { ... }
// only derive Show for assert_eq! in tests and debug builds
#[cfg_attr(any(test, not(ndebug)), deriving(Show))]
struct Foo { ... }
// ignore a test in certain cases
#[test]
#[cfg_attr(all(not(target_os = "linux"), target_endian = "big"), ignore)]
fn test_broken_thing() { ... }
// Avoid duplication when fixing staging issues in rustc
#[cfg_attr(not(stage0), lang="iter")]
pub trait Iterator<T> { ... }
```
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/cfg_attr.rs | 59 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 1 |
3 files changed, 62 insertions, 0 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b35a9456757..79dc623f507 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -439,6 +439,8 @@ fn initial_syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(intern("cfg"), builtin_normal_expander( ext::cfg::expand_cfg)); + syntax_expanders.insert(intern("cfg_attr"), + ItemModifier(ext::cfg_attr::expand)); syntax_expanders.insert(intern("trace_macros"), builtin_normal_expander( ext::trace_macros::expand_trace_macros)); diff --git a/src/libsyntax/ext/cfg_attr.rs b/src/libsyntax/ext/cfg_attr.rs new file mode 100644 index 00000000000..5df94ac526d --- /dev/null +++ b/src/libsyntax/ext/cfg_attr.rs @@ -0,0 +1,59 @@ +// 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. + +use std::gc::{Gc, GC}; + +use ast; +use attr; +use codemap::Span; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; + +pub fn expand(cx: &mut ExtCtxt, sp: Span, mi: Gc<ast::MetaItem>, it: Gc<ast::Item>) + -> Gc<ast::Item> { + let (cfg, attr) = match mi.node { + ast::MetaList(_, ref mis) if mis.len() == 2 => (mis[0], mis[1]), + _ => { + cx.span_err(sp, "expected `#[cfg_attr(<cfg pattern>, <attr>)]`"); + return it; + } + }; + + let mut out = (*it).clone(); + if cfg_matches(cx, cfg) { + out.attrs.push(cx.attribute(attr.span, attr)); + } + + box(GC) out +} + +fn cfg_matches(cx: &mut ExtCtxt, cfg: Gc<ast::MetaItem>) -> bool { + match cfg.node { + ast::MetaList(ref pred, ref mis) if pred.get() == "any" => + mis.iter().any(|mi| cfg_matches(cx, *mi)), + ast::MetaList(ref pred, ref mis) if pred.get() == "all" => + mis.iter().all(|mi| cfg_matches(cx, *mi)), + ast::MetaList(ref pred, ref mis) if pred.get() == "not" => { + if mis.len() != 1 { + cx.span_err(cfg.span, format!("expected 1 value, got {}", + mis.len()).as_slice()); + return false; + } + !cfg_matches(cx, mis[0]) + } + ast::MetaList(ref pred, _) => { + cx.span_err(cfg.span, + format!("invalid predicate `{}`", pred).as_slice()); + false + }, + ast::MetaWord(_) | ast::MetaNameValue(..) => + attr::contains(cx.cfg.as_slice(), cfg), + } +} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 153b3cc90d6..7a504d22c1e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -83,6 +83,7 @@ pub mod ext { pub mod build; pub mod bytes; pub mod cfg; + pub mod cfg_attr; pub mod concat; pub mod concat_idents; pub mod deriving; |
