use btree_range_map::{AnyRange, RangeMap};
use quote::quote;
use crate::{
charset,
utils::{automaton, MergeRef},
CharSet,
};
use super::{Token, TokenRange, TokenSet};
impl Token for char {
type Range = AnyRange<char>;
type Set = CharSet;
const UNICODE: bool = true;
fn from_u8(b: u8) -> Self {
b as char
}
fn from_char(c: char) -> Option<Self> {
Some(c)
}
fn from_u32(v: u32) -> Option<Self> {
char::from_u32(v)
}
fn is_ascii(automaton: &automaton::DetAutomaton<u32, Self::Set>) -> bool {
for transitions in automaton.transitions().values() {
if transitions.keys().any(|set| !set.is_ascii()) {
return false;
}
}
true
}
fn rust_type() -> proc_macro2::TokenStream {
quote!(char)
}
fn rust_string_type() -> proc_macro2::TokenStream {
quote!(str)
}
fn rust_owned_string_type() -> proc_macro2::TokenStream {
quote!(String)
}
fn rust_iterator_method() -> proc_macro2::TokenStream {
quote!(chars())
}
fn rust_as_inner_method() -> proc_macro2::TokenStream {
quote!(as_str)
}
fn rust_into_inner_method() -> proc_macro2::TokenStream {
quote!(into_string)
}
fn rust_inner_as_bytes_method() -> Option<proc_macro2::TokenStream> {
Some(quote!(as_bytes))
}
fn rust_inner_into_bytes_method() -> Option<proc_macro2::TokenStream> {
Some(quote!(into_bytes))
}
fn rust_empty_string() -> proc_macro2::TokenStream {
quote! {
""
}
}
}
impl TokenRange<char> for AnyRange<char> {
fn new(a: char, b: char) -> Self {
(a..=b).into()
}
}
impl TokenSet<char> for CharSet {
fn singleton(token: char, case_sensitive: bool) -> Self {
CharSet::from_char(token, case_sensitive)
}
fn rust_set(&self) -> proc_macro2::TokenStream {
let ranges = self.ranges().map(|range| match range.len() {
0 => panic!("empty range"),
1 => {
let a = range.first().unwrap();
quote! {
#a
}
}
_ => {
let a = range.first().unwrap();
let b = range.last().unwrap();
quote! {
#a..=#b
}
}
});
quote! { #(#ranges)|* }
}
}
impl MergeRef for CharSet {
fn merge_with_ref(&mut self, other: &Self) {
self.extend(other.ranges())
}
}
impl automaton::DeterminizeLabel for CharSet {
type Range = AnyRange<char>;
type Ranges<'a> = charset::Ranges<'a>;
type RangeMap<V: Clone + PartialEq> = RangeMap<char, V>;
fn ranges(&self) -> Self::Ranges<'_> {
CharSet::ranges(self)
}
fn insert_range(&mut self, range: <char as Token>::Range) {
self.insert(range)
}
}
impl<V: Clone + PartialEq> automaton::RangeMap<AnyRange<char>, V> for RangeMap<char, V> {
fn update(&mut self, key: AnyRange<char>, f: impl Fn(Option<&V>) -> Option<V>) {
RangeMap::update(self, key, f)
}
}