Files
x2/sub/_macros/src/patterns.rs
2025-11-28 02:12:33 -05:00

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
}