use std::fmt::Display;
#[derive(Debug)]
pub enum Transition {
Jump(JumpTransition), Char(CharTransition), AnyChar(AnyCharTransition), String(StringTransition), CharSet(CharSetTransition), BackReference(BackReferenceTransition), LineBoundaryAssertion(LineBoundaryAssertionTransition), WordBoundaryAssertion(WordBoundaryAssertionTransition),
CaptureStart(CaptureStartTransition),
CaptureEnd(CaptureEndTransition),
CounterReset(CounterResetTransition), CounterIncrement(CounterIncrementTransition),
RepetitionForward(RepetitionForwardTransition),
RepetitionBack(RepetitionBackTransition),
LookAheadAssertion(LookAheadAssertionTransition),
LookBehindAssertion(LookBehindAssertionTransition),
}
#[derive(Debug)]
pub struct JumpTransition;
#[derive(Debug)]
pub struct CharTransition {
pub codepoint: u32, pub byte_length: usize, }
#[derive(Debug)]
pub struct AnyCharTransition;
#[derive(Debug)]
pub struct StringTransition {
pub codepoints: Vec<u32>, pub byte_length: usize, }
#[derive(Debug)]
pub struct CharSetTransition {
pub items: Vec<CharSetItem>, pub negative: bool, }
#[derive(Debug)]
pub enum CharSetItem {
Char(u32), Range(CharRange), }
#[derive(Debug)]
pub struct CharRange {
pub start: u32, pub end_inclusive: u32, }
#[derive(Debug)]
pub struct BackReferenceTransition {
pub capture_group_index: usize, }
#[derive(Debug)]
pub struct LineBoundaryAssertionTransition {
pub is_end: bool,
}
#[derive(Debug)]
pub struct WordBoundaryAssertionTransition {
pub is_negative: bool,
}
#[derive(Debug)]
pub struct CaptureStartTransition {
pub capture_group_index: usize, }
#[derive(Debug)]
pub struct CaptureEndTransition {
pub capture_group_index: usize, }
#[derive(Debug)]
pub struct CounterResetTransition {
pub counter_index: usize, }
#[derive(Debug)]
pub struct CounterIncrementTransition {
pub counter_index: usize, }
#[derive(Debug)]
pub struct RepetitionForwardTransition {
pub repetition_type: RepetitionType, }
#[derive(Debug)]
pub struct RepetitionBackTransition {
pub repetition_type: RepetitionType, }
#[derive(Debug)]
pub struct LookAheadAssertionTransition {
pub route_index: usize, pub is_negative: bool, }
#[derive(Debug)]
pub struct LookBehindAssertionTransition {
pub route_index: usize, pub is_negative: bool, pub match_length_in_char: usize, }
impl CharTransition {
pub fn new(c: char) -> Self {
let byte_length = c.len_utf8();
CharTransition {
codepoint: (c as u32),
byte_length,
}
}
}
impl StringTransition {
pub fn new(s: &str) -> Self {
let chars: Vec<u32> = s.chars().map(|item| item as u32).collect();
let byte_length = s.len();
StringTransition {
codepoints: chars,
byte_length,
}
}
}
impl CharSetItem {
pub fn new_char(character: char) -> Self {
CharSetItem::Char(character as u32)
}
pub fn new_range(start: char, end_inclusive: char) -> Self {
let char_range = CharRange {
start: start as u32,
end_inclusive: end_inclusive as u32,
};
CharSetItem::Range(char_range)
}
}
impl CharSetTransition {
pub fn new(items: Vec<CharSetItem>, negative: bool) -> Self {
CharSetTransition { items, negative }
}
pub fn new_preset_charset_word() -> Self {
let mut items: Vec<CharSetItem> = vec![];
add_preset_word(&mut items);
CharSetTransition::new(items, false)
}
pub fn new_preset_charset_not_word() -> Self {
let mut items: Vec<CharSetItem> = vec![];
add_preset_word(&mut items);
CharSetTransition::new(items, true)
}
pub fn new_preset_charset_space() -> Self {
let mut items: Vec<CharSetItem> = vec![];
add_preset_space(&mut items);
CharSetTransition::new(items, false)
}
pub fn new_preset_charset_not_space() -> Self {
let mut items: Vec<CharSetItem> = vec![];
add_preset_space(&mut items);
CharSetTransition::new(items, true)
}
pub fn new_preset_charset_digit() -> Self {
let mut items: Vec<CharSetItem> = vec![];
add_preset_digit(&mut items);
CharSetTransition::new(items, false)
}
pub fn new_preset_charset_not_digit() -> Self {
let mut items: Vec<CharSetItem> = vec![];
add_preset_digit(&mut items);
CharSetTransition::new(items, true)
}
}
pub fn add_char(items: &mut Vec<CharSetItem>, c: char) {
items.push(CharSetItem::new_char(c));
}
pub fn add_range(items: &mut Vec<CharSetItem>, start: char, end_inclusive: char) {
items.push(CharSetItem::new_range(start, end_inclusive));
}
pub fn add_preset_space(items: &mut Vec<CharSetItem>) {
add_char(items, ' ');
add_char(items, '\t');
add_char(items, '\r');
add_char(items, '\n');
}
pub fn add_preset_word(items: &mut Vec<CharSetItem>) {
add_range(items, 'A', 'Z');
add_range(items, 'a', 'z');
add_range(items, '0', '9');
add_char(items, '_');
}
pub fn add_preset_digit(items: &mut Vec<CharSetItem>) {
add_range(items, '0', '9');
}
impl BackReferenceTransition {
pub fn new(capture_group_index: usize) -> Self {
BackReferenceTransition {
capture_group_index,
}
}
}
impl LineBoundaryAssertionTransition {
pub fn new(is_end: bool) -> Self {
LineBoundaryAssertionTransition { is_end }
}
}
impl WordBoundaryAssertionTransition {
pub fn new(is_negative: bool) -> Self {
WordBoundaryAssertionTransition { is_negative }
}
}
impl CaptureStartTransition {
pub fn new(capture_group_index: usize) -> Self {
CaptureStartTransition {
capture_group_index,
}
}
}
impl CaptureEndTransition {
pub fn new(capture_group_index: usize) -> Self {
CaptureEndTransition {
capture_group_index,
}
}
}
impl CounterResetTransition {
pub fn new(counter_index: usize) -> Self {
CounterResetTransition { counter_index }
}
}
impl CounterIncrementTransition {
pub fn new(counter_index: usize) -> Self {
CounterIncrementTransition { counter_index }
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum RepetitionType {
Repeat(usize),
RepeatFrom(usize),
RepeatRange(usize, usize),
}
impl RepetitionForwardTransition {
pub fn new(repetition_type: RepetitionType) -> Self {
RepetitionForwardTransition { repetition_type }
}
}
impl RepetitionBackTransition {
pub fn new(repetition_type: RepetitionType) -> Self {
RepetitionBackTransition { repetition_type }
}
}
impl LookAheadAssertionTransition {
pub fn new(route_index: usize, is_negative: bool) -> Self {
LookAheadAssertionTransition {
route_index,
is_negative,
}
}
}
impl LookBehindAssertionTransition {
pub fn new(route_index: usize, is_negative: bool, match_length_in_char: usize) -> Self {
LookBehindAssertionTransition {
route_index,
is_negative,
match_length_in_char,
}
}
}
impl Display for Transition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Transition::Jump(t) => write!(f, "{}", t),
Transition::Char(t) => write!(f, "{}", t),
Transition::String(t) => write!(f, "{}", t),
Transition::CharSet(t) => write!(f, "{}", t),
Transition::AnyChar(t) => write!(f, "{}", t),
Transition::BackReference(t) => write!(f, "{}", t),
Transition::LineBoundaryAssertion(t) => write!(f, "{}", t),
Transition::WordBoundaryAssertion(t) => write!(f, "{}", t),
Transition::CaptureStart(t) => write!(f, "{}", t),
Transition::CaptureEnd(t) => write!(f, "{}", t),
Transition::CounterReset(t) => write!(f, "{}", t),
Transition::CounterIncrement(t) => write!(f, "{}", t),
Transition::RepetitionForward(t) => write!(f, "{}", t),
Transition::RepetitionBack(t) => write!(f, "{}", t),
Transition::LookAheadAssertion(t) => write!(f, "{}", t),
Transition::LookBehindAssertion(t) => write!(f, "{}", t),
}
}
}
impl Display for JumpTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Jump")
}
}
fn escape_char(c: char) -> String {
match c {
'\n' => "\\n".to_string(),
'\r' => "\\r".to_string(),
'\t' => "\\t".to_string(),
'\\' => "\\\\".to_string(),
'\'' => "\\\'".to_string(),
'\"' => "\\\"".to_string(),
_ => c.to_string(),
}
}
impl Display for CharTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let c = unsafe { char::from_u32_unchecked(self.codepoint) };
write!(f, "Char '{}'", escape_char(c))
}
}
impl Display for AnyCharTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Any char")
}
}
impl Display for StringTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = self
.codepoints
.iter()
.map(|item| unsafe { char::from_u32_unchecked(*item) })
.map(escape_char)
.collect::<Vec<String>>()
.join("");
write!(f, "String \"{}\"", s)
}
}
impl Display for CharSetTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut lines = vec![];
for item in &self.items {
let line = match item {
CharSetItem::Char(codepoint) => {
let c = unsafe { char::from_u32_unchecked(*codepoint) };
format!("'{}'", escape_char(c))
}
CharSetItem::Range(r) => {
let start = unsafe { char::from_u32_unchecked(r.start) };
let end_inclusive = unsafe { char::from_u32_unchecked(r.end_inclusive) };
format!("'{}'..'{}'", escape_char(start), escape_char(end_inclusive))
}
};
lines.push(line);
}
let content = lines.join(", ");
if self.negative {
write!(f, "Charset ![{}]", content)
} else {
write!(f, "Charset [{}]", content)
}
}
}
impl Display for BackReferenceTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Back reference {{{}}}", self.capture_group_index)
}
}
impl Display for LineBoundaryAssertionTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_end {
write!(f, "Line boundary assertion is_end()")
} else {
write!(f, "Line boundary assertion is_start()")
}
}
}
impl Display for WordBoundaryAssertionTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_negative {
write!(f, "Word boundary assertion is_not_bound()")
} else {
write!(f, "Word boundary assertion is_bound()")
}
}
}
impl Display for CaptureStartTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Capture start {{{}}}", self.capture_group_index)
}
}
impl Display for CaptureEndTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Capture end {{{}}}", self.capture_group_index)
}
}
impl Display for CounterResetTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Counter reset")
}
}
impl Display for CounterIncrementTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Counter increment")
}
}
impl Display for RepetitionForwardTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Repetition forward {}", self.repetition_type)
}
}
impl Display for RepetitionBackTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Repetition back {}", self.repetition_type)
}
}
impl Display for RepetitionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RepetitionType::Repeat(n) => write!(f, "[{}]", n),
RepetitionType::RepeatFrom(m) => write!(f, "[{}..]", m),
RepetitionType::RepeatRange(m, n) => write!(f, "[{}..{}]", m, n),
}
}
}
impl Display for LookAheadAssertionTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_negative {
write!(f, "Look ahead negative ${}", self.route_index)
} else {
write!(f, "Look ahead ${}", self.route_index)
}
}
}
impl Display for LookBehindAssertionTransition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_negative {
write!(
f,
"Look behind negative ${}, match length {}",
self.route_index, self.match_length_in_char
)
} else {
write!(
f,
"Look behind ${}, match length {}",
self.route_index, self.match_length_in_char
)
}
}
}