use std::collections::HashMap;
#[cfg(feature = "derive")]
pub use dyck_derive::DyckToken;
pub trait DyckToken: Clone + Copy + Eq + std::hash::Hash {}
impl DyckToken for &str {}
pub type Word<T> = Vec<T>;
pub struct Language<T>
where
T: DyckToken,
{
alphabet: Vec<T>,
open_to_close: HashMap<T, T>,
close_to_open: HashMap<T, T>,
}
impl<T> Language<T>
where
T: DyckToken,
{
pub fn new_from_vec(pairs: &Vec<(T, T)>) -> Result<Self, &'static str> {
let mut alphabet = Vec::new();
let mut open_to_close = HashMap::new();
let mut close_to_open = HashMap::new();
for &(open, close) in pairs {
if alphabet.contains(&open) || alphabet.contains(&close) {
return Err("Duplicate token in the alphabet.");
}
alphabet.push(open);
alphabet.push(close);
open_to_close.insert(open, close);
close_to_open.insert(close, open);
}
Ok(Self {
alphabet,
open_to_close,
close_to_open,
})
}
pub fn new_from_arr(pairs: &[(T, T)]) -> Result<Self, &'static str> {
Self::new_from_vec(&pairs.to_vec())
}
pub fn get_k(&self) -> usize {
self.alphabet.len() / 2
}
pub fn is_open(&self, token: T) -> bool {
self.open_to_close.contains_key(&token)
}
pub fn is_close(&self, token: T) -> bool {
self.close_to_open.contains_key(&token)
}
pub fn is_valid(&self, word: &Word<T>) -> bool {
let mut stack = Vec::new();
for &token in word {
if self.is_open(token) {
stack.push(token);
} else if self.is_close(token) {
if let Some(&last) = stack.last() {
if self.open_to_close[&last] == token {
stack.pop();
} else {
return false;
}
} else {
return false;
}
}
}
stack.is_empty()
}
pub fn is_balanced(&self, word: &Word<T>) -> bool {
let mut count = 0;
for &token in word {
if self.is_open(token) {
count += 1;
} else if self.is_close(token) {
count -= 1;
}
if count < 0 {
return false;
}
}
count == 0
}
pub fn longest_valid_prefix(&self, word: &Word<T>) -> usize {
let mut stack = Vec::new();
let mut length = 0;
for (i, &token) in word.iter().enumerate() {
if self.is_open(token) {
stack.push(token);
} else if self.is_close(token) {
if let Some(&last) = stack.last() {
if self.open_to_close[&last] == token {
stack.pop();
if stack.is_empty() {
length = i + 1;
}
} else {
break;
}
} else {
break;
}
}
}
length
}
pub fn shortest_validating_appendage(&self, word: &Word<T>) -> Option<Word<T>> {
let mut stack = Vec::new();
let mut completed_word = word.clone();
for &token in word {
if self.is_open(token) {
stack.push(token);
} else if self.is_close(token) {
if let Some(&last) = stack.last() {
if self.open_to_close[&last] == token {
stack.pop();
}
} else if stack.is_empty() {
return None;
}
}
}
for token in stack.into_iter().rev() {
if let Some(close_token) = self.get_close(token) {
completed_word.push(close_token);
}
}
Some(completed_word)
}
pub fn get_close(&self, open: T) -> Option<T> {
self.open_to_close.get(&open).copied()
}
pub fn get_open(&self, close: T) -> Option<T> {
self.close_to_open.get(&close).copied()
}
}