pelite_macros/
lib.rs

1use proc_macro::*;
2
3/// Compile time pattern parser.
4///
5/// ```ignore
6/// const PATTERN: &[pelite::pattern::Atom] = pattern!("pattern string");
7/// ```
8#[proc_macro]
9pub fn pattern(input: TokenStream) -> TokenStream {
10	let input = input.into_iter().collect::<Vec<_>>();
11
12	let string = match &input[..] {
13		[TokenTree::Literal(lit)] => parse_str_literal(&lit),
14		_ => panic!("expected a single string literal to parse"),
15	};
16
17	let pattern = match pattern::parse(&string) {
18		Ok(pattern) => pattern,
19		Err(err) => panic!("invalid pattern syntax: {}", err),
20	};
21
22	format!("{{ use ::pelite::pattern::Atom::*; &{:?} }}", pattern).parse().unwrap()
23}
24
25fn parse_str_literal(input: &Literal) -> String {
26	let input = input.to_string();
27	let mut chars = input.chars();
28	let mut string = String::new();
29	if chars.next() != Some('"') {
30		panic!("expected string literal starting with a `\"` and no extraneous whitespace");
31	}
32	loop {
33		let chr = match chars.next() {
34			Some('\\') => {
35				match chars.next() {
36					Some('\\') => '\\',
37					Some('\'') => '\'',
38					Some('\"') => '\"',
39					Some('t') => '\t',
40					Some('r') => '\r',
41					Some('n') => '\n',
42					Some('u') => panic!("unicode escape sequence not supported"),
43					Some(chr) => panic!("unknown escape sequence: {}", chr),
44					None => panic!(""),
45				}
46			},
47			Some('"') => break,
48			Some(chr) => chr,
49			None => panic!("unexpected end of string literal, missing `\"` terminator?"),
50		};
51		string.push(chr);
52	}
53	string
54}
55
56// Total hack to get the pattern parse code in here :)
57#[allow(unused)]
58mod pattern;