Skip to content

Commit c1cc7e5

Browse files
lilyballdguenther
authored andcommitted
Add new syntax extension fourcc!()
fourcc!() allows you to embed FourCC (or OSType) values that are evaluated as u32 literals. It takes a 4-byte ASCII string and produces the u32 resulting in interpreting those 4 bytes as a u32, using either the platform-native endianness, or explicitly as big or little endian.
1 parent b66ec34 commit c1cc7e5

9 files changed

+206
-0
lines changed

src/libsyntax/ext/base.rs

+3
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ pub fn syntax_expander_table() -> SyntaxEnv {
194194
syntax_expanders.insert(intern("bytes"),
195195
builtin_normal_expander(
196196
ext::bytes::expand_syntax_ext));
197+
syntax_expanders.insert(intern("fourcc"),
198+
builtin_normal_tt_no_ctxt(
199+
ext::fourcc::expand_syntax_ext));
197200
syntax_expanders.insert(intern("concat_idents"),
198201
builtin_normal_expander(
199202
ext::concat_idents::expand_syntax_ext));

src/libsyntax/ext/fourcc.rs

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
/* The compiler code necessary to support the fourcc! extension. */
12+
13+
// fourcc!() is called with a single 4-character string, and an optional ident
14+
// that is either `big` or `little`. If the ident is omitted it is assumed to
15+
// be the platform-native value. It returns a u32.
16+
17+
use ast;
18+
use attr::contains;
19+
use codemap::{Span, mk_sp};
20+
use ext::base::*;
21+
use ext::base;
22+
use ext::build::AstBuilder;
23+
use parse;
24+
use parse::token;
25+
26+
use std::ascii::AsciiCast;
27+
28+
pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult {
29+
let (expr, endian) = parse_tts(cx, tts);
30+
31+
let little = match endian {
32+
None => target_endian_little(cx, sp),
33+
Some(Ident{ident, span}) => match cx.str_of(ident).as_slice() {
34+
"little" => true,
35+
"big" => false,
36+
_ => {
37+
cx.span_err(span, "invalid endian directive in fourcc!");
38+
target_endian_little(cx, sp)
39+
}
40+
}
41+
};
42+
43+
let s = match expr.node {
44+
// expression is a literal
45+
ast::ExprLit(lit) => match lit.node {
46+
// string literal
47+
ast::lit_str(s) => {
48+
if !s.is_ascii() {
49+
cx.span_err(expr.span, "non-ascii string literal in fourcc!");
50+
} else if s.len() != 4 {
51+
cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
52+
}
53+
s
54+
}
55+
_ => {
56+
cx.span_err(expr.span, "unsupported literal in fourcc!");
57+
return MRExpr(cx.expr_lit(sp, ast::lit_uint(0u64, ast::ty_u32)));
58+
}
59+
},
60+
_ => {
61+
cx.span_err(expr.span, "non-literal in fourcc!");
62+
return MRExpr(cx.expr_lit(sp, ast::lit_uint(0u64, ast::ty_u32)));
63+
}
64+
};
65+
66+
let mut val = 0u32;
67+
if little {
68+
for byte in s.byte_rev_iter().take(4) {
69+
val = (val << 8) | (byte as u32);
70+
}
71+
} else {
72+
for byte in s.byte_iter().take(4) {
73+
val = (val << 8) | (byte as u32);
74+
}
75+
}
76+
let e = cx.expr_lit(sp, ast::lit_uint(val as u64, ast::ty_u32));
77+
MRExpr(e)
78+
}
79+
80+
struct Ident {
81+
ident: ast::Ident,
82+
span: Span
83+
}
84+
85+
fn parse_tts(cx: @ExtCtxt, tts: &[ast::token_tree]) -> (@ast::Expr, Option<Ident>) {
86+
let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_owned());
87+
let ex = p.parse_expr();
88+
let id = if *p.token == token::EOF {
89+
None
90+
} else {
91+
p.expect(&token::COMMA);
92+
let lo = p.span.lo;
93+
let ident = p.parse_ident();
94+
let hi = p.last_span.hi;
95+
Some(Ident{ident: ident, span: mk_sp(lo, hi)})
96+
};
97+
if *p.token != token::EOF {
98+
p.unexpected();
99+
}
100+
(ex, id)
101+
}
102+
103+
fn target_endian_little(cx: @ExtCtxt, sp: Span) -> bool {
104+
let meta = cx.meta_name_value(sp, @"target_endian", ast::lit_str(@"little"));
105+
contains(cx.cfg(), meta)
106+
}

src/libsyntax/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub mod ext {
9595
pub mod bytes;
9696
pub mod concat;
9797
pub mod concat_idents;
98+
pub mod fourcc;
9899
pub mod log_syntax;
99100
pub mod source_util;
100101

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let val = fourcc!("foo"); //~ ERROR string literal with len != 4 in fourcc!
13+
let val2 = fourcc!("fooba"); //~ ERROR string literal with len != 4 in fourcc!
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let val = fourcc!("foo ", bork); //~ ERROR invalid endian directive in fourcc!
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let v = fourcc!("fooλ"); //~ ERROR non-ascii string literal in fourcc!
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let val = fourcc!(foo); //~ ERROR non-literal in fourcc!
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let val = fourcc!(45f); //~ ERROR unsupported literal in fourcc!
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
static static_val: u32 = fourcc!("foo ");
12+
static static_val_le: u32 = fourcc!("foo ", little);
13+
static static_val_be: u32 = fourcc!("foo ", big);
14+
15+
fn main() {
16+
let val = fourcc!("foo ");
17+
let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
18+
assert_eq!(val, exp);
19+
20+
let val = fourcc!("foo ", big);
21+
assert_eq!(val, 0x666f6f20u32);
22+
23+
let val = fourcc!("foo ", little);
24+
assert_eq!(val, 0x206f6f66u32);
25+
26+
let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
27+
assert_eq!(static_val, exp);
28+
assert_eq!(static_val_le, 0x206f6f66u32);
29+
assert_eq!(static_val_be, 0x666f6f20u32);
30+
}

0 commit comments

Comments
 (0)