(index<- )        ./libfourcc/lib.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2014 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  /*!
  12  Syntax extension to generate FourCCs.
  13  
  14  Once loaded, fourcc!() is called with a single 4-character string,
  15  and an optional ident that is either `big`, `little`, or `target`.
  16  The ident represents endianness, and specifies in which direction
  17  the characters should be read. If the ident is omitted, it is assumed
  18  to be `big`, i.e. left-to-right order. It returns a u32.
  19  
  20  # Examples
  21  
  22  To load the extension and use it:
  23  
  24  ```rust,ignore
  25  #[phase(syntax)]
  26  extern crate fourcc;
  27  
  28  fn main() {
  29      let val = fourcc!("\xC0\xFF\xEE!");
  30      assert_eq!(val, 0xC0FFEE21u32);
  31      let little_val = fourcc!("foo ", little);
  32      assert_eq!(little_val, 0x21EEFFC0u32);
  33  }
  34  ```
  35  
  36  # References
  37  
  38  * [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)
  39  
  40  */
  41  
  42  #![crate_id = "fourcc#0.11-pre"]
  43  #![crate_type = "rlib"]
  44  #![crate_type = "dylib"]
  45  #![license = "MIT/ASL2"]
  46  #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
  47         html_favicon_url = "http://www.rust-lang.org/favicon.ico",
  48         html_root_url = "http://static.rust-lang.org/doc/master")]
  49  
  50  #![deny(deprecated_owned_vector)]
  51  #![feature(macro_registrar, managed_boxes)]
  52  
  53  extern crate syntax;
  54  
  55  use syntax::ast;
  56  use syntax::ast::Name;
  57  use syntax::attr::contains;
  58  use syntax::codemap::{Span, mk_sp};
  59  use syntax::ext::base;
  60  use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
  61  use syntax::ext::build::AstBuilder;
  62  use syntax::parse;
  63  use syntax::parse::token;
  64  use syntax::parse::token::InternedString;
  65  
  66  #[macro_registrar]
  67  pub fn macro_registrar(register: |Name, SyntaxExtension|) {
  68      register(token::intern("fourcc"),
  69          NormalTT(box BasicMacroExpander {
  70              expander: expand_syntax_ext,
  71              span: None,
  72          },
  73          None));
  74  }
  75  
  76  pub fn expand_syntax_ext(cx: &mut ExtCtxt, spSpan, tts: &[ast::TokenTree])
  77                           -> Box<base::MacResult> {
  78      let (expr, endian) = parse_tts(cx, tts);
  79  
  80      let little = match endian {
  81          None => false,
  82          Some(Ident{ident, span}) => match token::get_ident(ident).get() {
  83              "little" => true,
  84              "big" => false,
  85              "target" => target_endian_little(cx, sp),
  86              _ => {
  87                  cx.span_err(span, "invalid endian directive in fourcc!");
  88                  target_endian_little(cx, sp)
  89              }
  90          }
  91      };
  92  
  93      let s = match expr.node {
  94          // expression is a literal
  95          ast::ExprLit(ref lit) => match lit.node {
  96              // string literal
  97              ast::LitStr(ref s, _) => {
  98                  if s.get().char_len() != 4 {
  99                      cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
 100                  }
 101                  s
 102              }
 103              _ => {
 104                  cx.span_err(expr.span, "unsupported literal in fourcc!");
 105                  return base::DummyResult::expr(sp)
 106              }
 107          },
 108          _ => {
 109              cx.span_err(expr.span, "non-literal in fourcc!");
 110              return base::DummyResult::expr(sp)
 111          }
 112      };
 113  
 114      let mut val = 0u32;
 115      for codepoint in s.get().chars().take(4) {
 116          let byte = if codepoint as u32 > 0xFF {
 117              cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
 118              0u8
 119          } else {
 120              codepoint as u8
 121          };
 122  
 123          val = if little {
 124              (val >> 8) | ((byte as u32) << 24)
 125          } else {
 126              (val << 8) | (byte as u32)
 127          };
 128      }
 129      let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
 130      MacExpr::new(e)
 131  }
 132  
 133  struct Ident {
 134      ident: ast::Ident,
 135      span: Span
 136  }
 137  
 138  fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
 139      let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
 140                                              cx.cfg(),
 141                                              tts.iter()
 142                                                 .map(|x| (*x).clone())
 143                                                 .collect());
 144      let ex = p.parse_expr();
 145      let id = if p.token == token::EOF {
 146          None
 147      } else {
 148          p.expect(&token::COMMA);
 149          let lo = p.span.lo;
 150          let ident = p.parse_ident();
 151          let hi = p.last_span.hi;
 152          Some(Ident{ident: ident, span: mk_sp(lo, hi)})
 153      };
 154      if p.token != token::EOF {
 155          p.unexpected();
 156      }
 157      (ex, id)
 158  }
 159  
 160  fn target_endian_little(cx: &ExtCtxt, spSpan) -> bool {
 161      let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
 162          ast::LitStr(InternedString::new("little"), ast::CookedStr));
 163      contains(cx.cfg().as_slice(), meta)
 164  }
 165  
 166  // FIXME (10872): This is required to prevent an LLVM assert on Windows
 167  #[test]
 168  fn dummy_test() { }