83 lines
2.4 KiB
Rust
83 lines
2.4 KiB
Rust
use core::{cmp, fmt, mem, str};
|
|
use proc_macro::{Delimiter, Literal, TokenStream, TokenTree};
|
|
|
|
|
|
mod atoms {
|
|
include!("../../xpat/src/atoms.rs");
|
|
}
|
|
|
|
mod parser {
|
|
include!("../../xpat/src/parser.rs");
|
|
}
|
|
|
|
/// Compile time pattern parser.
|
|
///
|
|
/// ```ignore
|
|
/// const PATTERN: &[pelite::pattern::Atom] = pattern!("pattern string");
|
|
/// ```
|
|
pub fn proc_pattern(input: TokenStream) -> TokenStream {
|
|
let mut string = String::new();
|
|
parse_tokens(input, &mut string);
|
|
|
|
let pattern = match parser::parse(&string) {
|
|
Ok(pattern) => pattern,
|
|
Err(err) => panic!("invalid pattern syntax: {}", err),
|
|
};
|
|
|
|
format!("{{ use x::xpat::Atom::*; &{:?} as x::Pattern }}", pattern).parse().unwrap()
|
|
}
|
|
|
|
|
|
pub fn parse_tokens(input: TokenStream, out: &mut String) {
|
|
let input = input.into_iter().collect::<Vec<_>>();
|
|
for token in input {
|
|
match token {
|
|
TokenTree::Group(g) if g.delimiter() == Delimiter::None => {
|
|
parse_tokens(g.stream(), out);
|
|
}
|
|
|
|
TokenTree::Punct(p) if p.as_char() == ',' => {}
|
|
|
|
TokenTree::Literal(lit) => {
|
|
parse_str_literal(&lit, out);
|
|
}
|
|
|
|
TokenTree::Group(g) => { panic!("Unexpected Delimiter group") }
|
|
TokenTree::Ident(_) => { panic!("Unexpected identifier") }
|
|
TokenTree::Punct(p) => { panic!("Unexpected punctuation") }
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
fn parse_str_literal(input: &Literal, out: &mut String) {
|
|
let input = input.to_string();
|
|
let mut chars = input.chars();
|
|
if chars.next() != Some('"') {
|
|
panic!("expected string literal starting with a `\"` and no extraneous whitespace");
|
|
}
|
|
loop {
|
|
let chr = match chars.next() {
|
|
Some('\\') => {
|
|
match chars.next() {
|
|
Some('\\') => '\\',
|
|
Some('\'') => '\'',
|
|
Some('\"') => '\"',
|
|
Some('t') => '\t',
|
|
Some('r') => '\r',
|
|
Some('n') => '\n',
|
|
Some('u') => panic!("unicode escape sequence not supported"),
|
|
Some(chr) => panic!("unknown escape sequence: {}", chr),
|
|
None => panic!(""),
|
|
}
|
|
},
|
|
Some('"') => break,
|
|
Some(chr) => chr,
|
|
None => panic!("unexpected end of string literal, missing `\"` terminator?"),
|
|
};
|
|
out.push(chr);
|
|
}
|
|
}
|