1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
use super::{ Instruction, Address };
#[derive(Debug)]
pub(crate) enum ArgumentError {
UnknownInstruction,
TooMany,
TooFew,
NotLocation,
NotNumber,
NotString,
}
impl Instruction {
fn new_subleq(a: &Address, b: &Address, c: &Address) -> Instruction {
if let Address::Constants(_) = c {
panic!("Constants cannot be the third subleq argument!");
}
Instruction {
name: "subleq".to_string(),
args: vec![a.clone(), b.clone(), c.clone()],
}
}
fn check_args_len(&self, expected: usize) -> Result<(), ArgumentError> {
if self.args.len() < expected {
return Err(ArgumentError::TooFew);
}
else if self.args.len() > 3 {
return Err(ArgumentError::TooMany);
}
Ok(())
}
pub(crate) fn check_args(&self) -> Result<(), ArgumentError> {
match &*self.name {
"subleq" => {
self.check_args_len(3)?;
for arg in &self.args {
if ! arg.is_location() {
return Err(ArgumentError::NotLocation);
}
}
},
"jmp" => {
self.check_args_len(1)?;
if ! self.args[0].is_location() {
return Err(ArgumentError::NotLocation);
}
},
"add" => {
self.check_args_len(2)?;
},
"mov" => {
self.check_args_len(2)?;
if ! self.args[1].is_location() {
return Err(ArgumentError::NotLocation);
}
},
"beq" => {
self.check_args_len(2)?;
if ! self.args[1].is_location() {
return Err(ArgumentError::NotLocation);
}
},
_ => return Err(ArgumentError::UnknownInstruction),
}
Ok(())
}
pub(crate) fn collapse(&mut self, next: usize) -> Vec<Instruction> {
self.name = self.name.to_lowercase();
static Z: Address = Address::Memory(0);
match &*self.name {
"subleq" => vec![self.clone()],
"jmp" => vec![
Instruction::new_subleq(&Z, &Z, &self.args[0]),
],
"add" => vec![
Instruction::new_subleq(&self.args[0], &Z, &Address::Instruction(next + 1)),
Instruction::new_subleq(&Z, &self.args[1], &Address::Instruction(next + 2)),
Instruction::new_subleq(&Z, &Z, &Address::Instruction(next + 3)),
],
"mov" => vec![
Instruction::new_subleq(&self.args[1], &self.args[1], &Address::Instruction(next + 1)),
Instruction::new_subleq(&self.args[0], &Z, &Address::Instruction(next + 2)),
Instruction::new_subleq(&Z, &self.args[1], &Address::Instruction(next + 3)),
Instruction::new_subleq(&Z, &Z, &Address::Instruction(next + 4)),
],
"beq" => vec![
Instruction::new_subleq(&self.args[0], &Z, &Address::Instruction(next + 2)),
Instruction::new_subleq(&Z, &Z, &Address::Instruction(next + 4)),
Instruction::new_subleq(&Z, &Z, &Address::Instruction(next + 3)),
Instruction::new_subleq(&Z, &self.args[0], &self.args[1] ),
],
_ => panic!("Unknown instruction {}!", self.name),
}
}
pub(crate) fn collapse_len(&self) -> usize {
match &*self.name {
"subleq" | "jmp"
=> 1,
"add"
=> 3,
"mov" | "beq"
=> 4,
_ => panic!("Unknown instruction {}!", self.name),
}
}
}
|