about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2013-09-16 19:30:28 -0700
committerDerek Guenther <dguenther9@gmail.com>2014-02-08 23:40:16 -0600
commitc1cc7e5f164b0119fcd60d6c9ade31fbfcff4b55 (patch)
treec773589dde45c66030ad5d99fb9ee03355bb2a8e
parentb66ec3483bd5081bcc829efb88ceb841189b754d (diff)
downloadrust-c1cc7e5f164b0119fcd60d6c9ade31fbfcff4b55.tar.gz
rust-c1cc7e5f164b0119fcd60d6c9ade31fbfcff4b55.zip
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.
-rw-r--r--src/libsyntax/ext/base.rs3
-rw-r--r--src/libsyntax/ext/fourcc.rs106
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-bad-len.rs14
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-non-literal.rs13
-rw-r--r--src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs13
-rw-r--r--src/test/run-pass/syntax-extension-fourcc.rs30
9 files changed, 206 insertions, 0 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 848f4ba3871..bf240d8b47c 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -194,6 +194,9 @@ pub fn syntax_expander_table() -> SyntaxEnv {
     syntax_expanders.insert(intern("bytes"),
                             builtin_normal_expander(
                                     ext::bytes::expand_syntax_ext));
+    syntax_expanders.insert(intern("fourcc"),
+                            builtin_normal_tt_no_ctxt(
+                                    ext::fourcc::expand_syntax_ext));
     syntax_expanders.insert(intern("concat_idents"),
                             builtin_normal_expander(
                                     ext::concat_idents::expand_syntax_ext));
diff --git a/src/libsyntax/ext/fourcc.rs b/src/libsyntax/ext/fourcc.rs
new file mode 100644
index 00000000000..dd5452535a2
--- /dev/null
+++ b/src/libsyntax/ext/fourcc.rs
@@ -0,0 +1,106 @@
+// 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.
+
+/* The compiler code necessary to support the fourcc! extension. */
+
+// fourcc!() is called with a single 4-character string, and an optional ident
+// that is either `big` or `little`. If the ident is omitted it is assumed to
+// be the platform-native value. It returns a u32.
+
+use ast;
+use attr::contains;
+use codemap::{Span, mk_sp};
+use ext::base::*;
+use ext::base;
+use ext::build::AstBuilder;
+use parse;
+use parse::token;
+
+use std::ascii::AsciiCast;
+
+pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult {
+    let (expr, endian) = parse_tts(cx, tts);
+
+    let little = match endian {
+        None => target_endian_little(cx, sp),
+        Some(Ident{ident, span}) => match cx.str_of(ident).as_slice() {
+            "little" => true,
+            "big" => false,
+            _ => {
+                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::lit_str(s) => {
+                if !s.is_ascii() {
+                    cx.span_err(expr.span, "non-ascii string literal in fourcc!");
+                } else if s.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::lit_uint(0u64, ast::ty_u32)));
+            }
+        },
+        _ => {
+            cx.span_err(expr.span, "non-literal in fourcc!");
+            return MRExpr(cx.expr_lit(sp, ast::lit_uint(0u64, ast::ty_u32)));
+        }
+    };
+
+    let mut val = 0u32;
+    if little {
+        for byte in s.byte_rev_iter().take(4) {
+            val = (val << 8) | (byte as u32);
+        }
+    } else {
+        for byte in s.byte_iter().take(4) {
+            val = (val << 8) | (byte as u32);
+        }
+    }
+    let e = cx.expr_lit(sp, ast::lit_uint(val as u64, ast::ty_u32));
+    MRExpr(e)
+}
+
+struct Ident {
+    ident: ast::Ident,
+    span: Span
+}
+
+fn parse_tts(cx: @ExtCtxt, tts: &[ast::token_tree]) -> (@ast::Expr, Option<Ident>) {
+    let p = 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, @"target_endian", ast::lit_str(@"little"));
+    contains(cx.cfg(), meta)
+}
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 613416bed1c..5999cf0d8fe 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -95,6 +95,7 @@ pub mod ext {
     pub mod bytes;
     pub mod concat;
     pub mod concat_idents;
+    pub mod fourcc;
     pub mod log_syntax;
     pub mod source_util;
 
diff --git a/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs b/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs
new file mode 100644
index 00000000000..11e2264001f
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-fourcc-bad-len.rs
@@ -0,0 +1,14 @@
+// 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.
+
+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!
+}
diff --git a/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs b/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs
new file mode 100644
index 00000000000..ebad65ce740
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-fourcc-invalid-endian.rs
@@ -0,0 +1,13 @@
+// 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.
+
+fn main() {
+    let val = fourcc!("foo ", bork); //~ ERROR invalid endian directive in fourcc!
+}
diff --git a/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs b/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs
new file mode 100644
index 00000000000..94a963298e2
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-fourcc-non-ascii-str.rs
@@ -0,0 +1,13 @@
+// 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.
+
+fn main() {
+    let v = fourcc!("fooλ"); //~ ERROR non-ascii string literal in fourcc!
+}
diff --git a/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs b/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs
new file mode 100644
index 00000000000..baefd267e90
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-fourcc-non-literal.rs
@@ -0,0 +1,13 @@
+// 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.
+
+fn main() {
+    let val = fourcc!(foo); //~ ERROR non-literal in fourcc!
+}
diff --git a/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs b/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs
new file mode 100644
index 00000000000..ee191a7d96d
--- /dev/null
+++ b/src/test/compile-fail/syntax-extension-fourcc-unsupported-literal.rs
@@ -0,0 +1,13 @@
+// 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.
+
+fn main() {
+    let val = fourcc!(45f); //~ ERROR unsupported literal in fourcc!
+}
diff --git a/src/test/run-pass/syntax-extension-fourcc.rs b/src/test/run-pass/syntax-extension-fourcc.rs
new file mode 100644
index 00000000000..a5202144b77
--- /dev/null
+++ b/src/test/run-pass/syntax-extension-fourcc.rs
@@ -0,0 +1,30 @@
+// 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.
+
+static static_val: u32 = fourcc!("foo ");
+static static_val_le: u32 = fourcc!("foo ", little);
+static static_val_be: u32 = fourcc!("foo ", big);
+
+fn main() {
+    let val = fourcc!("foo ");
+    let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
+    assert_eq!(val, exp);
+
+    let val = fourcc!("foo ", big);
+    assert_eq!(val, 0x666f6f20u32);
+
+    let val = fourcc!("foo ", little);
+    assert_eq!(val, 0x206f6f66u32);
+
+    let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
+    assert_eq!(static_val, exp);
+    assert_eq!(static_val_le, 0x206f6f66u32);
+    assert_eq!(static_val_be, 0x666f6f20u32);
+}