Skip to content

Commit 357e81f

Browse files
Add unit test for opcode modifier table
1 parent 7f5b14d commit 357e81f

File tree

6 files changed

+115
-22
lines changed

6 files changed

+115
-22
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ authors = ["Ian Chamberlain <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
8+
itertools = "0.8.0"
89
lazy_static = "1.2.0"
910
pest_derive = "2.1.0"
1011
pest = "2.1.0"

src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
// Extern crates requiring macro_use
12
#[macro_use]
23
extern crate pest_derive;
4+
5+
// Extern crates
6+
extern crate itertools;
37
extern crate pest;
48

9+
pub use parser::parse;
10+
11+
// Modules requiring macro_use
512
#[macro_use]
613
mod util;
714

8-
pub mod parser;
9-
1015
mod load_file;
16+
mod parser;

src/load_file.rs

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ enum_string!(pub PseudoOpcode, {
3535
});
3636

3737
enum_string!(pub Modifier, {
38-
A => "A",
39-
B => "B",
40-
AB => "AB",
41-
BA => "BA",
42-
F => "F",
43-
X => "X",
44-
I => "I",
38+
A => "A",
39+
B => "B",
40+
AB => "AB",
41+
BA => "BA",
42+
F => "F",
43+
X => "X",
44+
I => "I",
4545
});
4646

4747
impl Default for Modifier {
@@ -52,6 +52,8 @@ impl Default for Modifier {
5252

5353
impl Modifier {
5454
pub fn from_context(opcode: Opcode, a_mode: AddressMode, b_mode: AddressMode) -> Modifier {
55+
/// Implemented based on the ICWS '94 document,
56+
/// section A.2.1.2: ICWS'88 to ICWS'94 Conversion
5557
use Opcode::*;
5658

5759
match opcode {
@@ -67,6 +69,7 @@ impl Modifier {
6769
Mov | Cmp | Seq | Sne => Modifier::I,
6870
Slt => Modifier::B,
6971
Add | Sub | Mul | Div | Mod => Modifier::F,
72+
_ => unreachable!(),
7073
}
7174
}
7275
}
@@ -75,14 +78,14 @@ impl Modifier {
7578
}
7679

7780
enum_string!(pub AddressMode, {
78-
Immediate => "#",
79-
Direct => "$",
80-
IndirectA => "*",
81-
IndirectB => "@",
82-
PreDecIndirectA => "{",
83-
PreDecIndirectB => "<",
84-
PostIncIndirectA => "}",
85-
PostIncIndirectB => ">",
81+
Immediate => "#",
82+
Direct => "$",
83+
IndirectA => "*",
84+
IndirectB => "@",
85+
PreDecIndirectA => "{",
86+
PreDecIndirectB => "<",
87+
PostIncIndirectA => "}",
88+
PostIncIndirectB => ">",
8689
});
8790

8891
impl Default for AddressMode {
@@ -214,8 +217,20 @@ impl PartialEq for Core {
214217

215218
#[cfg(test)]
216219
mod tests {
220+
use itertools::iproduct;
221+
use lazy_static::lazy_static;
222+
223+
use std::str::FromStr;
224+
217225
use super::*;
218226

227+
lazy_static! {
228+
static ref all_modes: vec::Vec<AddressMode> = ["#", "$", "@", "<", ">", "*", "{", "}"]
229+
.iter()
230+
.map(|mode_str| AddressMode::from_str(mode_str).unwrap())
231+
.collect();
232+
}
233+
219234
#[test]
220235
fn default_instruction() {
221236
let expected_instruction = Instruction {
@@ -233,4 +248,61 @@ mod tests {
233248

234249
assert_eq!(Instruction::default(), expected_instruction)
235250
}
251+
252+
#[test]
253+
fn dat_from_context() {
254+
for (&a_mode, &b_mode) in iproduct!(all_modes.iter(), all_modes.iter()) {
255+
assert_eq!(
256+
Modifier::from_context(Opcode::Dat, a_mode, b_mode),
257+
Modifier::F
258+
);
259+
}
260+
}
261+
262+
#[test]
263+
fn modifier_b_from_context() {
264+
use Opcode::*;
265+
266+
let opcodes = [Jmp, Jmz, Jmn, Djn, Spl, Nop];
267+
268+
for (&a_mode, &b_mode) in iproduct!(all_modes.iter(), all_modes.iter()) {
269+
for &opcode in opcodes.iter() {
270+
assert_eq!(Modifier::from_context(opcode, a_mode, b_mode), Modifier::B);
271+
}
272+
}
273+
274+
let a_modes: vec::Vec<AddressMode> = ["$", "@", "<", ">", "*", "{", "}"]
275+
.iter()
276+
.map(|mode_str| AddressMode::from_str(mode_str).unwrap())
277+
.collect();
278+
279+
for &a_mode in a_modes.iter() {
280+
for &b_mode in all_modes.iter() {
281+
assert_eq!(
282+
Modifier::from_context(Opcode::Slt, a_mode, b_mode),
283+
Modifier::B
284+
)
285+
}
286+
}
287+
288+
// TODO Mov, Cmp. Seq, Sne -> B
289+
}
290+
291+
#[test]
292+
fn modifier_ab_from_context() {
293+
use Opcode::*;
294+
295+
let opcodes = [Mov, Cmp, Seq, Sne, Add, Sub, Mul, Div, Mod, Slt];
296+
297+
for &b_mode in all_modes.iter() {
298+
for &opcode in opcodes.iter() {
299+
assert_eq!(
300+
Modifier::from_context(opcode, AddressMode::Immediate, b_mode),
301+
Modifier::AB
302+
);
303+
}
304+
}
305+
}
306+
307+
// TODO Mode I
236308
}

src/util.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ macro_rules! enum_string {
1818
$($variant,)*
1919
}
2020

21-
impl std::string::ToString for $name {
21+
impl ::std::string::ToString for $name {
2222
fn to_string(&self) -> String {
2323
use $name::*;
2424
match *self {
@@ -27,7 +27,7 @@ macro_rules! enum_string {
2727
}
2828
}
2929

30-
impl std::str::FromStr for $name {
30+
impl ::std::str::FromStr for $name {
3131
type Err = String;
3232
fn from_str(input_str: &str) -> Result<Self, Self::Err> {
3333
use $name::*;

tests/parse_and_dump.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
extern crate corewa_rs;
22

3-
use corewa_rs::parser;
4-
53
#[test]
64
fn test_parse() {
75
let test_warrior = include_str!("test_file.red");
86

97
println!("Parsing warrior:\n{}", test_warrior);
108

11-
let core = parser::parse(test_warrior).unwrap();
9+
let core = corewa_rs::parse(test_warrior).unwrap();
1210

1311
println!("Loaded core:\n{:?}", core);
1412

0 commit comments

Comments
 (0)