main.rs (9342B)
1 use std::collections::HashMap; 2 use std::env; 3 use std::fmt; 4 use std::fs; 5 use std::usize; 6 7 mod eval; 8 9 struct Program { 10 data: Vec<String>, 11 pc: usize, 12 vars: HashMap<char, String>, 13 funcs: HashMap<char, String> 14 } 15 16 impl Program { 17 fn from_string(program: String) -> Program { 18 let mut op_list: Vec<String> = Vec::new(); 19 20 for opcode in program.split("\n").collect::<Vec<&str>>() { 21 let new_op = opcode.to_owned(); 22 23 if new_op.len() != 0 { 24 op_list.push(new_op.to_owned()); 25 } 26 } 27 28 return Program { 29 data: op_list, 30 pc: 0, 31 vars: HashMap::new(), 32 funcs: HashMap::new() 33 }; 34 } 35 36 // Reads the arguments passed to an opcode, and inserts variables where necessary 37 fn args_or_vars(&self, arguments: &str) -> String { 38 let mut builder = String::from(""); // Empty string that will be rebuilt based on the loop 39 let argument_vec: Vec<char> = arguments.chars().collect(); // Deconstructed arguments 40 41 // Iterate through each char 42 for index in 0..argument_vec.len() { 43 let current_char = argument_vec[index]; 44 let str_to_push: String; 45 46 if index > 0 { 47 // Only test for the dollar sign if it's not the first character 48 // This is because there can't be anything before the first character, otherwise it's not the first 49 if argument_vec[index - 1] == '$' { 50 // If the previous character is a dollar sign, we can skip this iteration because we know the variable has already been handled 51 continue; 52 } 53 } 54 55 if current_char == '$' { 56 // If the current char is a $, we know that the next char should be a variable 57 let variable = argument_vec[index + 1]; 58 59 let key = self.vars.get(&variable); 60 match key { 61 Some(value) => str_to_push = value.to_string(), 62 None => panic!("NotFoundError: Variable {} has not been defined", variable), 63 } 64 } else { 65 // If there's no variable, then just push the char that was already there 66 str_to_push = current_char.to_string(); 67 } 68 69 builder.push_str(&str_to_push); 70 } 71 72 builder 73 } 74 75 fn add_var(&mut self, arguments: &str) { 76 let argument_vec: Vec<char> = arguments.chars().collect(); 77 let name = argument_vec[0]; 78 let mut value: String = argument_vec[1..].into_iter().collect(); 79 value = self.args_or_funcs(&value); 80 81 self.vars.insert(name, value); 82 } 83 84 fn add_func(&mut self, arguments: &str) { 85 let argument_vec: Vec<char> = arguments.chars().collect(); 86 let name = argument_vec[0]; 87 let body: String = argument_vec[1..].into_iter().collect(); 88 89 self.funcs.insert(name, body); 90 } 91 92 fn parse_funcs(&mut self, instruction: &String) -> u32 { 93 // Opcode is the first character, arguments are everything after the first char 94 let opcode = instruction.chars().collect::<Vec<char>>()[0]; 95 let arguments = &instruction[1..]; 96 97 // Only a subset of opcodes, because the others don't make sense in a function 98 match opcode { 99 'a' => eval::do_math(self.args_or_funcs(&self.args_or_vars(arguments)), '+'), 100 's' => eval::do_math(self.args_or_funcs(&self.args_or_vars(arguments)), '-'), 101 'm' => eval::do_math(self.args_or_funcs(&self.args_or_vars(arguments)), '*'), 102 'd' => eval::do_math(self.args_or_funcs(&self.args_or_vars(arguments)), '/'), 103 'l' => {self.add_var(arguments);0} 104 _ => panic!("SyntaxError: No such opcode: {}", self.pc), 105 } 106 } 107 108 fn args_or_funcs(&mut self, arguments: &str) -> String { 109 let mut builder = String::from(""); 110 let argument_vec: Vec<char> = arguments.chars().collect(); 111 112 for index in 0..argument_vec.len() { 113 let current_char = argument_vec[index]; 114 let str_to_push: String; 115 116 if index > 0 { 117 if argument_vec[index-1] == '*' { 118 continue; 119 } 120 } 121 122 if current_char == '*' { 123 let func_name = argument_vec[index+1]; 124 let body: String; 125 126 let key = (self).funcs.get(&func_name); 127 match key { 128 Some(content) => body = content.to_owned(), 129 None => panic!("ValueError: function {} has not been defined yet!", func_name) 130 } 131 132 str_to_push = self.parse_funcs(&body).to_string(); 133 } else { 134 str_to_push = current_char.to_string(); 135 } 136 137 builder.push_str(&str_to_push); 138 } 139 140 builder 141 } 142 143 fn run_external(&mut self, arguments: String) { 144 // Split arguments by - 145 let argument_vec: Vec<&str> = arguments.split("-").collect(); 146 println!("{}", argument_vec.len()); 147 let filename = argument_vec[0]; 148 149 // Read contents of the provided file and construct a symbolic Program from it 150 let contents = fs::read_to_string(filename).expect("Something went wrong reading the file"); 151 let mut prog = Program::from_string(contents); 152 prog.run(); 153 154 if argument_vec.len() > 1 { 155 // Start from the second element 156 for name in argument_vec[1..].iter() { 157 let kind = match name.chars().nth(0) { 158 Some(content) => content, 159 None => panic!("SyntaxError: {}: Invalid syntax", arguments) 160 }; 161 let name_to_import = match name.chars().nth(1) { 162 Some(content) => content, 163 None => panic!("SyntaxError: {}: Invalid syntax", arguments) 164 }; 165 if kind == 'v' { 166 let key = prog.vars.get(&name_to_import); 167 match key { 168 Some(value) => self.vars.insert(name_to_import, value.to_string()), 169 None => panic!("ValueError: variable {} has not been defined in {}!", name_to_import, filename) 170 }; 171 } else if kind == 'f' { 172 let key = prog.funcs.get(&name_to_import); 173 match key { 174 Some(value) => {self.funcs.insert(name_to_import, value.to_string());()}, 175 None => panic!("ValueError: function {} has not been defined in {}!", name_to_import, filename) 176 } 177 } else { 178 // Skip unknown types 179 continue; 180 } 181 } 182 } else { 183 // implied catch-all, might be unintuitive 184 for (key, value) in prog.vars.iter() { 185 self.vars.insert(*key, value.to_string()); 186 } 187 188 for (key, value) in prog.funcs.iter() { 189 self.funcs.insert(*key, value.to_string()); 190 } 191 } 192 } 193 194 fn parse(&mut self, instruction: &String) { 195 // Opcode is the first character, arguments are everything after the first char 196 let opcode = instruction.chars().collect::<Vec<char>>()[0]; 197 let arguments = eval::args_or_comments(&instruction[1..]); 198 199 if opcode != '#' { 200 match opcode { 201 'p' => println!("{}", self.args_or_funcs(&self.args_or_vars(&arguments))), 202 'a' => println!("{}", eval::do_math(self.args_or_vars(&arguments), '+')), 203 's' => println!("{}", eval::do_math(self.args_or_vars(&arguments), '-')), 204 'm' => println!("{}", eval::do_math(self.args_or_vars(&arguments), '*')), 205 'd' => println!("{}", eval::do_math(self.args_or_vars(&arguments), '/')), 206 'l' => self.add_var(&arguments), 207 'f' => self.add_func(&arguments), 208 'i' => self.run_external(arguments), 209 _ => panic!("SyntaxError at opcode {}: Unknown opcode {}", self.pc, opcode), 210 } 211 } 212 } 213 214 fn run(&mut self) { 215 println!("{}", self); 216 while self.pc < self.data.len() { 217 // Grab instruction from op list and parse the instruction 218 let instruction = self.data[self.pc].to_owned(); 219 220 self.parse(&instruction); 221 222 self.pc += 1; 223 } 224 } 225 } 226 227 impl fmt::Display for Program { 228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 229 write!(f, "Program ({:?})", self.data) 230 } 231 } 232 233 fn main() { 234 // Grab args and a filename 235 let args: Vec<String> = env::args().collect(); 236 if args.len() == 1 { 237 // Args will always have at least 1 argument, which is the name of the executable. 238 // That's why we're checking index 1, not index 0. 239 panic!("You must provide a filename!"); 240 } 241 242 let filename = &args[1]; 243 244 // Read contents of the provided file and construct a symbolic Program from it 245 let contents = fs::read_to_string(filename).expect("Something went wrong reading the file"); 246 let mut prog = Program::from_string(contents); 247 prog.run(); 248 } 249 250 #[cfg(test)] 251 mod tests;