An Odd Rewriting System/odd.rs
Jump to navigation
Jump to search
rust interpreter by User:Pro465. invoke as rustc odd.rs && ./odd filename [max_cycles] where the optional max_cycles argument specifies maximum number of cycles to execute
use std::collections::HashMap;
use std::fs;
fn main() {
let mut args = std::env::args();
let prog = fs::read_to_string(
fs::canonicalize(args.nth(1).unwrap_or_else(|| help()))
.expect("could not canonicalize argument"),
)
.expect("could not read file");
let mut state = State::parse(&prog);
let lim = args.next().map(|n| n.parse().unwrap_or_else(|_| help()));
if let Some(lim) = lim {
for _ in 0..=lim {
println!("{}", state.step());
}
} else {
loop {
println!("{}", state.step());
}
}
}
fn help() -> ! {
println!(
"usage: {} <filename> [max_iter]",
std::env::current_exe()
.unwrap_or_else(|_| "aors".into())
.display()
);
std::process::exit(-1);
}
fn is_valid(x: char) -> bool {
x.is_uppercase() || x.is_lowercase() || x == '$'
}
struct State<'a> {
inp: String,
rules: HashMap<char, [&'a str; 2]>,
}
impl<'a> State<'a> {
fn parse(prog: &'a str) -> Self {
let mut iter = prog
.lines()
.flat_map(|line| {
line.split_once('#')
.map(|i| i.0)
.unwrap_or(line)
.split_whitespace()
})
.filter(|x| !x.is_empty());
let inp = iter.next().unwrap().to_string();
let mut rules = HashMap::<_, [_; 2]>::new();
for rule in iter {
let parity = rule.as_bytes()[0];
assert!((b'0'..=b'1').contains(&parity));
let (sym, repl) = rule[1..].split_once(':').unwrap();
let sym = sym.chars().next().unwrap();
assert!(is_valid(sym));
assert!(repl.chars().all(is_valid));
rules.entry(sym).or_default()[(parity - b'0') as usize] = repl
}
Self { inp, rules }
}
fn step(&mut self) -> String {
let mut parity = 0;
let mut res = String::new();
for c in self.inp.chars() {
if c == '$' {
res = String::new();
break;
}
res.push_str(self.rules[&c][parity]);
parity ^= c.is_uppercase() as usize;
}
std::mem::replace(&mut self.inp, res)
}
}