1use std::str::FromStr;
4
5#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
7pub enum Port {
8 UP,
9 DOWN,
10 LEFT,
11 RIGHT,
12}
13
14use self::Port::*;
15
16#[derive(Debug, PartialEq)]
18pub struct ParsePortError;
19
20impl FromStr for Port {
21 type Err = ParsePortError;
22
23 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 match s {
25 "UP" => Ok(UP),
26 "DOWN" => Ok(DOWN),
27 "LEFT" => Ok(LEFT),
28 "RIGHT" => Ok(RIGHT),
29 _ => Err(ParsePortError)
30 }
31 }
32}
33
34pub fn opposite_port(port: Port) -> Port {
46 match port {
47 UP => DOWN,
48 DOWN => UP,
49 LEFT => RIGHT,
50 RIGHT => LEFT,
51 }
52}
53
54#[derive(Debug, PartialEq, Copy, Clone)]
56pub enum IoRegister {
57 DIR(Port),
58 ANY, LAST,
60}
61
62use self::IoRegister::*;
63
64#[derive(Debug, PartialEq)]
66pub struct ParseIoRegisterError;
67
68impl FromStr for IoRegister {
69 type Err = ParseIoRegisterError;
70
71 fn from_str(s: &str) -> Result<Self, Self::Err> {
72 match s {
73 "ANY" => Ok(ANY),
74 "LAST" => Ok(LAST),
75 _ => if let Ok(port) = str::parse::<Port>(s) {
76 Ok(DIR(port))
77 } else {
78 Err(ParseIoRegisterError)
79 }
80 }
81 }
82}
83
84#[derive(Debug, PartialEq, Copy, Clone)]
86pub enum Register {
87 ACC,
88 NIL,
89 IO(IoRegister),
90}
91
92use self::Register::*;
93
94#[derive(Debug, PartialEq)]
96pub struct ParseRegisterError;
97
98impl FromStr for Register {
99 type Err = ParseRegisterError;
100
101 fn from_str(s: &str) -> Result<Self, Self::Err> {
102 match s {
103 "ACC" => Ok(ACC),
104 "NIL" => Ok(NIL),
105 _ => {
106 if let Ok(reg) = str::parse::<IoRegister>(s) {
107 Ok(IO(reg))
108 } else {
109 Err(ParseRegisterError)
110 }
111 }
112 }
113 }
114}
115
116#[derive(Debug, PartialEq, Copy, Clone)]
118pub enum Source {
119 VAL(isize),
120 REG(Register),
121}
122
123use self::Source::*;
124
125#[derive(Debug, PartialEq)]
127pub struct ParseSourceError;
128
129impl FromStr for Source {
130 type Err = ParseSourceError;
131
132 fn from_str(s: &str) -> Result<Self, Self::Err> {
133 if let Ok(val) = str::parse::<isize>(s) {
134 Ok(VAL(val))
135 } else if let Ok(register) = str::parse::<Register>(s) {
136 Ok(REG(register))
137 } else {
138 Err(ParseSourceError)
139 }
140 }
141}
142
143#[derive(Debug, PartialEq, Copy, Clone)]
145pub enum Instruction {
146 Nop,
147 Mov(Source, Register),
148 Swp,
149 Sav,
150 Add(Source),
151 Sub(Source),
152 Neg,
153 Jmp(isize),
154 Jez(isize),
155 Jnz(isize),
156 Jgz(isize),
157 Jlz(isize),
158 Jro(Source),
159}
160
161pub type Program = Vec<Instruction>;
164
165#[test]
166fn test_parse_port() {
167 assert_eq!(str::parse::<Port>("UP"), Ok(UP));
168 assert_eq!(str::parse::<Port>("DOWN"), Ok(DOWN));
169 assert_eq!(str::parse::<Port>("LEFT"), Ok(LEFT));
170 assert_eq!(str::parse::<Port>("RIGHT"), Ok(RIGHT));
171 assert_eq!(str::parse::<Port>("up"), Err(ParsePortError));
172 assert_eq!(str::parse::<Port>("bad"), Err(ParsePortError));
173}
174
175#[test]
176fn test_parse_io_register() {
177 assert_eq!(str::parse::<IoRegister>("UP"), Ok(DIR(UP)));
178 assert_eq!(str::parse::<IoRegister>("ANY"), Ok(ANY));
179 assert_eq!(str::parse::<IoRegister>("LAST"), Ok(LAST));
180 assert_eq!(str::parse::<IoRegister>("any"), Err(ParseIoRegisterError));
181 assert_eq!(str::parse::<IoRegister>("bad"), Err(ParseIoRegisterError));
182}
183
184#[test]
185fn test_parse_register() {
186 assert_eq!(str::parse::<Register>("ACC"), Ok(ACC));
187 assert_eq!(str::parse::<Register>("NIL"), Ok(NIL));
188 assert_eq!(str::parse::<Register>("UP"), Ok(IO(DIR(UP))));
189 assert_eq!(str::parse::<Register>("acc"), Err(ParseRegisterError));
190 assert_eq!(str::parse::<Register>("bad"), Err(ParseRegisterError));
191}
192
193#[test]
194fn test_parse_source() {
195 assert_eq!(str::parse::<Source>("ACC"), Ok(REG(ACC)));
196 assert_eq!(str::parse::<Source>("1"), Ok(VAL(1)));
197 assert_eq!(str::parse::<Source>("bad"), Err(ParseSourceError));
198}