Skip to content

Add new syntax extension fourcc!() #9255

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

Closed
wants to merge 1 commit into from
Closed
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: 3 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ pub fn syntax_expander_table() -> SyntaxEnv {
syntax_expanders.insert(intern("bytes"),
builtin_normal_tt_no_ctxt(
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_tt_no_ctxt(
ext::concat_idents::expand_syntax_ext));
Expand Down
106 changes: 106 additions & 0 deletions src/libsyntax/ext/fourcc.rs
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions src/libsyntax/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub mod ext {
pub mod format;
pub mod env;
pub mod bytes;
pub mod fourcc;
pub mod concat_idents;
pub mod log_syntax;
pub mod auto_encode;
Expand Down
14 changes: 14 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,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!
}
13 changes: 13 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,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!
}
13 changes: 13 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,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!
}
13 changes: 13 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,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!
}
Original file line number Diff line number Diff line change
@@ -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!
}
30 changes: 30 additions & 0 deletions src/test/run-pass/syntax-extension-fourcc.rs
Original file line number Diff line number Diff line change
@@ -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);
}