1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#![feature(plugin_registrar, rustc_private, slice_patterns)]
extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;
use std::rc::Rc;
use rustc_plugin::Registry;
use syntax::ast::LitKind::ByteStr;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::tokenstream::TokenTree;
fn decode_hex_str(hex: &str) -> Result<Vec<u8>, String> {
let mut vec = Vec::with_capacity(hex.len() / 2);
let mut filtered = hex.chars().filter(|&c| !c.is_whitespace());
while let Some(first) = filtered.next() {
let hi = try!(decode_hex_char(first));
if let Some(second) = filtered.next() {
let lo = try!(decode_hex_char(second));
vec.push((hi << 4) | lo)
} else {
return Err("odd number of hex characters".into());
}
}
Ok(vec)
}
fn decode_hex_char(c: char) -> Result<u8, String> {
if let Some(digit) = c.to_digit(16) {
Ok(digit as u8)
} else {
Err(format!("non-hexadecimal non-whitespace character {:?}", c))
}
}
fn expand_hex(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult + 'static> {
match *args {
[TokenTree::Token(tok_span, token::Literal(token::Str_(name), _))] => {
match decode_hex_str(&name.as_str()) {
Ok(bytes) => {
let byte_str = ByteStr(Rc::new(bytes));
return MacEager::expr(cx.expr_lit(sp, byte_str));
}
Err(reason) => cx.span_err(tok_span, &reason),
}
}
[ref tt] => cx.span_err(tt.span(), "expected string literal"),
[_, ref tt, ..] => cx.span_err(tt.span(), "too many arguments"),
_ => cx.span_err(sp, "expected string literal"),
}
DummyResult::any(sp)
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("hex", expand_hex);
}