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::>(); 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 }