!run:echo "#![doc = include_str!(\"../README.md\")]"
use gstring::{GString, GStringTrait, Grapheme};
use std::collections::BTreeMap;
!run:../bin/matching.pl
pub trait FindMatching {
fn find_matching(
&self,
position: usize,
closing: &BTreeMap<&str, &str>,
opening: &BTreeMap<&str, &str>,
) -> usize;
}
impl FindMatching for str {
fn find_matching(&self,
position: usize,
closing: &BTreeMap<&str, &str>,
opening: &BTreeMap<&str, &str>,
) -> usize {
self.gstring().find_matching(position, closing, opening)
}
}
impl FindMatching for GString {
fn find_matching(&self,
position: usize,
closing: &BTreeMap<&str, &str>,
opening: &BTreeMap<&str, &str>,
) -> usize {
let v = self.graphemes();
if position >= v.len() {
return position;
}
let close = closing.get(&v[position].as_str());
let open = opening.get(&v[position].as_str());
if close.is_none() && open.is_none() {
return position;
}
let mut stack: Vec<(usize, &Grapheme)> = vec![];
for (i, g) in v.iter().enumerate() {
if let Some(open) = opening.get(&g.as_str()) {
if let Some(prev) = stack.pop() {
if prev.1 == open {
if prev.0 == position {
return i;
} else if i == position {
return prev.0;
}
} else if closing.contains_key(&g.as_str()) {
stack.push(prev);
stack.push((i, g));
} else {
return position;
}
} else if closing.contains_key(&g.as_str()) {
stack.push((i, g));
}
} else if closing.contains_key(&g.as_str()) {
stack.push((i, g));
}
}
position
}
}