Minreg the Cat/minreg.rs
Jump to navigation
Jump to search
use std::io::{self, Write};
fn main() {
let mut lines = io::stdin().lines().map(Result::unwrap);
let mut prompt = |s| {
print!("{s}");
io::stdout().flush().unwrap();
lines.next()
};
let regex = prompt("Enter Minreg expression: ").expect("could not read regex from input");
let tree = Tree::new(®ex);
while let Some(line) = prompt("Enter string: ") {
if tree.matches(&line) {
println!("matched")
} else {
println!("did not match")
}
}
}
#[derive(Debug)]
enum Tree {
Any, // .
Or(Vec<Tree>), // |
Kleene(Box<Tree>), // *
Group(Vec<Tree>), // ,
Literal(char),
}
impl Tree {
fn new(regex: &str) -> Self {
let mut stack = Vec::new();
let mut iter = regex.chars();
while let Some(x) = iter.next() {
if !",.|\\*".contains(x) {
stack.push(Tree::Literal(x));
} else if x == '\\' {
stack.push(Tree::Literal(
iter.next().expect("why tf wud u put \\ @ da end??"),
));
} else {
if x == '.' {
stack.push(Tree::Any);
} else {
let b = stack.pop().expect("empty stack");
if x == '*' {
stack.push(Tree::Kleene(Box::new(b)));
continue;
}
let mut a = stack.pop().expect("empty stack");
match x {
'|' => match &mut a {
Tree::Or(v) => v.push(b),
_ => a = Tree::Or(vec![a, b]),
},
',' => match &mut a {
Tree::Group(v) => v.push(b),
_ => a = Tree::Group(vec![a, b]),
},
_ => unreachable!(),
}
stack.push(a);
}
}
}
Tree::Group(stack)
}
fn matches(&self, s: &str) -> bool {
let (b, idx) = self.matches_priv(s);
b && s.len() == idx
}
fn matches_priv(&self, s: &str) -> (bool, usize) {
let mut idx = 0;
let fail = (false, 0);
match self {
Tree::Any => {
if let Some(c) = s.chars().next() {
(true, c.len_utf8())
} else {
fail
}
}
Tree::Literal(c) => {
if Some(*c) == s.chars().next() {
(true, c.len_utf8())
} else {
fail
}
}
Tree::Group(v) => {
for m in v {
if let (true, i) = m.matches_priv(&s[idx..]) {
idx += i;
} else {
return fail;
}
}
(true, idx)
}
Tree::Or(v) => {
for m in v {
if let (true, i) = m.matches_priv(s) {
return (true, i);
}
}
fail
}
Tree::Kleene(b) => {
while let (true, i) = b.matches_priv(&s[idx..]) {
idx += i;
}
(true, idx)
}
}
}
}