64 lines
1.9 KiB
Rust
64 lines
1.9 KiB
Rust
use core::{cmp, fmt, mem, str};
|
|
use proc_macro::{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 input = input.into_iter().collect::<Vec<_>>();
|
|
|
|
let string = match &input[..] {
|
|
[TokenTree::Literal(lit)] => parse_str_literal(&lit),
|
|
_e => panic!("expected a single string literal to parse, got: {_e:?}"),
|
|
};
|
|
|
|
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()
|
|
}
|
|
|
|
fn parse_str_literal(input: &Literal) -> String {
|
|
let input = input.to_string();
|
|
let mut chars = input.chars();
|
|
let mut string = String::new();
|
|
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?"),
|
|
};
|
|
string.push(chr);
|
|
}
|
|
string
|
|
}
|