turing_lib/
instruction.rs1use std::{fmt::Display, str::FromStr};
2
3use crate::{turing::Rule, CompilerError, ErrorPosition};
4use pest::iterators::Pairs;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
8pub enum Movement {
10 RIGHT,
11 LEFT,
12 HALT,
13}
14
15impl std::str::FromStr for Movement {
16 type Err = String;
17
18 fn from_str(input: &str) -> Result<Self, Self::Err> {
20 match input {
21 "R" | "D" => Ok(Self::RIGHT),
22 "L" | "I" => Ok(Self::LEFT),
23 "H" | "N" => Ok(Self::HALT),
24 _ => Err(format!("\"{input}\" is an unknown movement")),
25 }
26 }
27}
28
29impl Display for Movement {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 Movement::RIGHT => write!(f, "R"),
34 Movement::LEFT => write!(f, "L"),
35 Movement::HALT => write!(f, "H"),
36 }
37 }
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct TuringInstruction {
43 pub from_state: String,
44 pub from_value: bool,
45 pub to_value: bool,
46 pub movement: Movement,
47 pub to_state: String,
48}
49
50impl Display for TuringInstruction {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 write!(
54 f,
55 "({}, {}, {}, {}, {})",
56 self.from_state,
57 if self.from_value { "1" } else { "0" },
58 if self.to_value { "1" } else { "0" },
59 self.movement,
60 self.to_state
61 )
62 }
63}
64
65impl TuringInstruction {
66 pub fn from(mut code: Pairs<Rule>) -> Result<Self, CompilerError> {
68 let from_state = match code.next() {
69 Some(s) => String::from(s.as_span().as_str()),
70 None => panic!("The instruction lacks an initial state"),
71 };
72 let from_value = match code.next() {
73 Some(s) => s.as_span().as_str() == "1",
74 None => panic!("The instruction lacks an initial tape value"),
75 };
76 let to_value = match code.next() {
77 Some(s) => s.as_span().as_str() == "1",
78 None => panic!("The instruction lacks a target tape value"),
79 };
80
81 let movement = match code.next() {
82 Some(s) => match Movement::from_str(s.as_span().as_str()) {
83 Ok(m) => m,
84 Err(message) => {
85 return Err(CompilerError::SyntaxError {
86 position: ErrorPosition::from(&s),
87 message,
88 code: String::from(s.as_str()),
89 expected: Rule::movement,
90 found: None,
91 })
92 }
93 },
94 None => panic!("The instruction lacks an initial state"),
95 };
96
97 let to_state = match code.next() {
98 Some(s) => String::from(s.as_span().as_str()),
99 None => panic!("The instruction lacks a target state"),
100 };
101
102 Ok(Self {
103 from_state,
104 from_value,
105 to_value,
106 movement,
107 to_state,
108 })
109 }
110
111 pub fn halt(index: (String, bool)) -> Self {
113 Self {
114 from_state: index.0.clone(),
115 from_value: index.1,
116 to_value: index.1,
117 movement: Movement::HALT,
118 to_state: index.0,
119 }
120 }
121}