Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add syntax extension fourcc!() #12034

Merged
merged 4 commits into from
Feb 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
################################################################################

TARGET_CRATES := std extra green rustuv native flate arena glob term semver \
uuid serialize sync getopts collections
uuid serialize sync getopts collections fourcc
HOST_CRATES := syntax rustc rustdoc
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc
Expand All @@ -74,6 +74,7 @@ DEPS_uuid := std serialize
DEPS_sync := std
DEPS_getopts := std
DEPS_collections := std serialize
DEPS_fourcc := syntax std

TOOL_DEPS_compiletest := extra green rustuv getopts
TOOL_DEPS_rustdoc := rustdoc green rustuv
Expand Down
160 changes: 160 additions & 0 deletions src/libfourcc/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// 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.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern mod fourcc;

fn main() {
let val = fourcc!("\xC0\xFF\xEE!")
// val is 0xC0FFEE21
let big_val = fourcc!("foo ", big);
// big_val is 0x21EEFFC0
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#[crate_id = "fourcc#0.10-pre"];
#[crate_type = "rlib"];
#[crate_type = "dylib"];
#[license = "MIT/ASL2"];

#[feature(macro_registrar, managed_boxes)];

extern mod syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
#[cfg(not(test))]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
register(token::intern("fourcc"),
NormalTT(~BasicMacroExpander {
expander: expand_syntax_ext,
span: None,
},
None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
let (expr, endian) = parse_tts(cx, tts);

let little = match endian {
None => false,
Some(Ident{ident, span}) => match token::get_ident(ident.name).get() {
"little" => true,
"big" => false,
"target" => target_endian_little(cx, sp),
_ => {
cx.span_err(span, "invalid endian directive in fourcc!");
target_endian_little(cx, sp)
}
}
};

let s = match expr.node {
// expression is a literal
ast::ExprLit(lit) => match lit.node {
// string literal
ast::LitStr(ref s, _) => {
if s.get().char_len() != 4 {
cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
}
s
}
_ => {
cx.span_err(expr.span, "unsupported literal in fourcc!");
return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
}
},
_ => {
cx.span_err(expr.span, "non-literal in fourcc!");
return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
}
};

let mut val = 0u32;
for codepoint in s.get().chars().take(4) {
let byte = if codepoint as u32 > 0xFF {
cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
0u8
} else {
codepoint as u8
};

val = if little {
(val >> 8) | ((byte as u32) << 24)
} else {
(val << 8) | (byte as u32)
};
}
let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
MRExpr(e)
}

struct Ident {
ident: ast::Ident,
span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
let p = &mut parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_owned());
let ex = p.parse_expr();
let id = if p.token == token::EOF {
None
} else {
p.expect(&token::COMMA);
let lo = p.span.lo;
let ident = p.parse_ident();
let hi = p.last_span.hi;
Some(Ident{ident: ident, span: mk_sp(lo, hi)})
};
if p.token != token::EOF {
p.unexpected();
}
(ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
ast::LitStr(InternedString::new("little"), ast::CookedStr));
contains(cx.cfg(), meta)
}

// Fixes LLVM assert on Windows
#[test]
fn dummy_test() { }
5 changes: 4 additions & 1 deletion src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,13 @@ impl Visitor<()> for Context {
self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
stable enough for use and is subject to change");
}

else if id == self.sess.ident_of("trace_macros") {
self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
stable enough for use and is subject to change");
} else {
}

else {
for &quote in quotes.iter() {
if id == self.sess.ident_of(quote) {
self.gate_feature("quote", path.span, quote + msg);
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down
23 changes: 23 additions & 0 deletions src/test/compile-fail/syntax-extension-fourcc-bad-len.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-stage1
// xfail-pretty
// xfail-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

fn main() {
let val = fourcc!("foo"); //~ ERROR string literal with len != 4 in fourcc!
let val2 = fourcc!("fooba"); //~ ERROR string literal with len != 4 in fourcc!
}
22 changes: 22 additions & 0 deletions src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-stage1
// xfail-pretty
// xfail-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

fn main() {
let val = fourcc!("foo ", bork); //~ ERROR invalid endian directive in fourcc!
}
22 changes: 22 additions & 0 deletions src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

// xfail-stage1
// xfail-pretty
// xfail-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

fn main() {
let v = fourcc!("fooλ"); //~ ERROR fourcc! literal character out of range 0-255
}
22 changes: 22 additions & 0 deletions src/test/compile-fail/syntax-extension-fourcc-non-literal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

// xfail-stage1
// xfail-pretty
// xfail-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

fn main() {
let val = fourcc!(foo); //~ ERROR non-literal in fourcc!
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

// xfail-stage1
// xfail-pretty
// xfail-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

fn main() {
let val = fourcc!(45f32); //~ ERROR unsupported literal in fourcc!
}
45 changes: 45 additions & 0 deletions src/test/run-pass-fulldeps/syntax-extension-fourcc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.

// xfail-fast Feature gating doesn't work
// xfail-stage1
// xfail-pretty
// xfail-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

static static_val: u32 = fourcc!("foo ");
static static_val_be: u32 = fourcc!("foo ", big);
static static_val_le: u32 = fourcc!("foo ", little);
static static_val_target: u32 = fourcc!("foo ", target);

fn main() {
let val = fourcc!("foo ", big);
assert_eq!(val, 0x666f6f20u32);
assert_eq!(val, fourcc!("foo "));

let val = fourcc!("foo ", little);
assert_eq!(val, 0x206f6f66u32);

let val = fourcc!("foo ", target);
let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
assert_eq!(val, exp);

assert_eq!(static_val_be, 0x666f6f20u32);
assert_eq!(static_val, static_val_be);
assert_eq!(static_val_le, 0x206f6f66u32);
let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
assert_eq!(static_val_target, exp);

assert_eq!(fourcc!("\xC0\xFF\xEE!"), 0xC0FFEE21);
}