use std::fmt;
use crate::instruction::Head;
use crate::program::Program;
use crate::state::Configuration;
use crate::{Symbol, TuringMachine, With};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Classic<S: Symbol> {
default: S,
program: Program<S>,
}
impl<S: Symbol> Classic<S> {
pub fn new(program: Program<S>, default: S) -> Result<Self, String> {
match program.alphabet().contains(&default) {
true => Ok(Classic { program, default }),
false => Err(format!(
"new error: default symbol {} is not in alphabet {:?}",
default,
program.alphabet()
)),
}
}
}
impl<S: Symbol> TuringMachine<S> for Classic<S> {
fn execute_once(&self, mut conf: Configuration<S>) -> Result<Configuration<S>, String> {
let head = Head::new(conf.state, conf.get_symbol().clone());
let inst = match self.program.get(&head)? {
Some(inst) => inst,
None => {
return Err(format!(
"uncovered case: have no tail for head ({}) in program",
head
))
}
};
conf.state = inst.tail.state;
conf.set_symbol(inst.tail.symbol.clone());
conf.shift(inst.tail.movement, self.default.clone());
Ok(conf)
}
fn execute_until(
&self,
mut conf: Configuration<S>,
until: impl Fn(&Configuration<S>) -> bool,
) -> Result<Configuration<S>, String> {
while !until(&conf) {
let head = Head::new(conf.state, conf.get_symbol().clone());
let inst = match self.program.get(&head)? {
Some(inst) => inst,
None => {
return Err(format!(
"uncovered case: have no tail for head ({}) in program",
head
))
}
};
conf.state = inst.tail.state;
conf.set_symbol(inst.tail.symbol.clone());
conf.shift(inst.tail.movement, self.default.clone());
}
Ok(conf)
}
}
impl<S: Symbol> With<Classic<S>> for Classic<S> {
type Output = Result<Classic<S>, String>;
fn with(&self, other: &Classic<S>) -> Self::Output {
if self.default != other.default {
return Err(format!(
"with error: classic machines have different default symbols: {} and {}",
self.default, other.default,
));
}
let program = self.program.with(&other.program)?;
Classic::new(program, self.default.clone())
}
}
impl<S: Symbol> With<Classic<S>> for Result<Classic<S>, String> {
type Output = Result<Classic<S>, String>;
fn with(&self, other: &Classic<S>) -> Self::Output {
match self {
Ok(machine) => machine.with(other),
Err(msg) => Err(msg.clone()),
}
}
}
impl<S: Symbol> fmt::Display for Classic<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
use std::any::type_name;
write!(
f,
"Classic<{}> {{ program: {} }}",
type_name::<S>(),
self.program
)
}
}