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
65
66
67
68
69
extern crate proc_macro;
use proc_macro::{TokenStream, TokenTree};
use proc_macro_hack::proc_macro_hack;

#[proc_macro_hack]
pub fn wide_str(ts: TokenStream) -> TokenStream {
    let mut iter = ts.into_iter();
    if let Some(TokenTree::Literal(lit)) = iter.next() {
        if iter.next().is_some() {
            panic!("Invalid argument(s)!");
        }
        let old: String = lit.to_string();
        let mut new: String = String::new();
        let len = old.len();

        let mut iter = old.chars().skip(1).take(len - 2);
        while let Some(c) = iter.next() {
            if c == '\\' {
                new.push(match iter.next().unwrap() {
                    'n' => '\n',
                    'r' => '\r',
                    't' => '\t',
                    '0' => '\0',
                    
                    'x' => {
                        let mut code_iter = (&mut iter).take(2);
                        if (&mut code_iter).count() != 2 {
                            panic!(r"this form of character escape may only be used with characters in the range [\x00-\x7f]");
                        }
                        let parsed = u8::from_str_radix(&code_iter.collect::<String>(), 16).unwrap_or_else(|_| panic!("Syntax Error: ASCII hex escape code must contain only hex characters"));
                        if parsed > b'\x7F' {
                            panic!("Syntax Error: ASCII hex escape code must be at most 0x7F");
                        }
                        parsed as char
                    },
                    'u' => {
                        if iter.next() != Some('{') {
                            panic!("Syntax Error: Missing `{` to begin the unicode escape");
                        }
                        let code_iter = (&mut iter).take_while(|x| *x != '}').filter(|x| *x != '_').enumerate();
                        let parsed = u32::from_str_radix(&code_iter.map(|val| {
                            let (i, c) = val;
                            if i > 6 {
                                panic!("Syntax Error: Unicode escape code must have at most 6 digits");
                            }
                            c
                        }).collect::<String>(), 16).unwrap_or_else(|_| panic!("Syntax Error: ASCII hex escape code must contain only hex characters"));
                        core::char::from_u32(parsed).expect("Syntax Error: Unicode escape code must be at most 0x10FFFF")
                    },

                    c => c,
                });
            } else {
                new.push(c);
            }
        }
        new.push('\0');

        let mut result = "[".to_string();
        for c in new.chars() {
            result.push_str(&format!("0x{:x}, ", c as u16));
        }
        result.push(']');

        result.parse().unwrap()
    } else {
        panic!("Invalid argument(s)!");
    }
}