A Quadrilateral Cowboy clone intended to help me learn Game Dev
at rust-bevy 350 lines 11 kB view raw
1use bevy::prelude::*; 2 3#[derive(Component)] 4pub struct TerminalSystem; 5 6#[derive(Clone, Debug)] 7enum Token { 8 Identifier(String), 9 Integer(i32), 10 Period, 11 Semicolon, 12 LParen, 13 RParen 14} 15 16impl std::fmt::Display for Token { 17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 18 match self { 19 Token::Identifier(id) => write!(f, "Identifer({})", id), 20 Token::Integer(int) => write!(f, "Integer({})", int), 21 Token::LParen => write!(f, "("), 22 Token::RParen => write!(f, ")"), 23 Token::Period => write!(f, "."), 24 Token::Semicolon => write!(f, ";") 25 } 26 } 27} 28 29#[derive(Debug)] 30pub enum CallArg { 31 Integer(i32) 32} 33 34#[derive(Debug)] 35pub struct CallNode { 36 target: Option<String>, 37 method: String, 38 args: Vec<CallArg> 39} 40 41impl std::fmt::Display for CallNode { 42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 43 write!(f, "{}{}({})", match &self.target { 44 Some(val) => { 45 val.to_owned() + "." 46 }, 47 None => "".into() 48 }, self.method, { 49 let mut str_args: Vec<String> = Vec::new(); 50 51 for arg in &self.args { 52 match arg { 53 CallArg::Integer(int) => { 54 str_args.push(int.to_string()); 55 } 56 } 57 } 58 59 str_args.join(", ") 60 }) 61 } 62} 63 64#[derive(Event)] 65pub struct TerminalEvent(Vec<CallNode>); 66 67impl TerminalEvent { 68 pub fn new(nodes: Vec<CallNode>) -> Self { 69 Self(nodes) 70 } 71} 72 73#[derive(Component)] 74pub struct TerminalObject(String, TObjectType); 75 76impl TerminalObject { 77 pub fn new(val: String, object_type: TObjectType) -> Self { 78 Self(val.to_owned(), object_type) 79 } 80} 81 82pub enum TObjectType { 83 Door, 84 Laser 85} 86 87pub fn plugin(app: &mut App) { 88 app.add_observer(|event: On<TerminalEvent>, terminal_objects: Query<&TerminalObject>| { 89 for node in &event.0 { 90 if node.method == "wait" && matches!(node.target, None) { 91 // call wait 92 } else { 93 if matches!(node.target, None) { 94 panic!("invalid target None"); 95 } 96 97 if let Some(obj) = terminal_objects.iter().find(|o| o.0 == *node.target.as_ref().unwrap()) { 98 match obj.1 { 99 TObjectType::Door => { 100 if node.method == "open" { 101 // call open 102 println!("open door {}", obj.0); 103 } else if node.method == "close" { 104 // call close 105 println!("close door {}", obj.0); 106 } else { 107 panic!("invalid method door.{}", node.method); 108 } 109 }, 110 TObjectType::Laser => { 111 if node.method == "on" { 112 // call on 113 println!("turn on laser {}", obj.0); 114 } else if node.method == "off" { 115 // call off 116 println!("turn off laser {}", obj.0); 117 } else { 118 panic!("invalid method laser.{}", node.method); 119 } 120 } 121 } 122 } else { 123 panic!("invalid target {}", node.target.as_ref().unwrap()); 124 } 125 } 126 } 127 }); 128} 129 130impl TerminalSystem { 131 pub fn parse(&mut self, input: String) -> Vec<CallNode> { 132 let tokens = self.lex(input); 133 self.parse_tokens(tokens) 134 } 135 136 fn lex(&mut self, input: String) -> Vec<Token> { 137 let mut tokens = Vec::new(); 138 let mut buffer = String::new(); 139 let mut in_id = false; 140 let mut in_int = false; 141 142 let mut iter = 0; 143 144 while iter < input.len() { 145 let chr = input.chars().skip(iter).take(1).collect::<String>(); 146 147 if in_id { 148 if chr.chars().any(|c| matches!(c, 'a'..='z')) || "0123456789".contains(&chr) { 149 buffer += &chr; 150 iter += 1; 151 continue; 152 } else { 153 tokens.push(Token::Identifier(buffer.clone())); 154 in_id = false; 155 continue; 156 } 157 } else if in_int { 158 if "0123456789".contains(&chr) { 159 buffer += &chr; 160 iter += 1; 161 continue; 162 } else { 163 tokens.push(Token::Integer(buffer.parse::<i32>().unwrap())); 164 in_int = false; 165 continue; 166 } 167 } else if chr == ";" { 168 tokens.push(Token::Semicolon); 169 iter += 1; 170 continue; 171 } else if chr == "." { 172 tokens.push(Token::Period); 173 iter += 1; 174 continue; 175 } else if chr == "(" { 176 tokens.push(Token::LParen); 177 iter += 1; 178 continue; 179 } else if chr == ")" { 180 tokens.push(Token::RParen); 181 iter += 1; 182 continue; 183 } else if chr == " " { 184 iter += 1; 185 continue; 186 } else if chr.chars().any(|c| matches!(c, 'a'..='z') || matches!(c, 'A'..='Z')) { 187 in_id = true; 188 buffer = chr.clone(); 189 iter += 1; 190 continue; 191 } else if "0123456789".contains(&chr) { 192 if !in_int { 193 in_int = true; 194 buffer = chr.clone(); 195 iter += 1; 196 continue; 197 } 198 } else { 199 panic!("Need to figure out how to throw errors"); 200 } 201 } 202 203 tokens 204 } 205 206 fn parse_tokens(&mut self, tokens: Vec<Token>) -> Vec<CallNode> { 207 let mut nodes = Vec::new(); 208 let mut iter = 0; 209 210 let consume = |tokens: &Vec<Token>, mut iter: &mut usize, expected_type: Option<Token>| -> Token { 211 let token = { 212 if *iter < tokens.len() { 213 Some(&tokens[*iter]) 214 } else { 215 None 216 } 217 }; 218 219 if let Some(exp_type) = expected_type { 220 if let Some(Token::Identifier(_)) = token { 221 if let Token::Identifier(_) = exp_type { 222 (*iter) += 1; 223 (*token.unwrap()).clone() 224 } else { 225 panic!("Expected type not found"); 226 } 227 } else if let Some(Token::Integer(_)) = token { 228 if let Token::Integer(_) = exp_type { 229 (*iter) += 1; 230 (*token.unwrap()).clone() 231 } else { 232 panic!("Expected type not found"); 233 } 234 } else if let Some(Token::LParen) = token { 235 if let Token::LParen = exp_type { 236 (*iter) += 1; 237 (*token.unwrap()).clone() 238 } else { 239 panic!("Expected type not found"); 240 } 241 } else if let Some(Token::Period) = token { 242 if let Token::Period = exp_type { 243 (*iter) += 1; 244 (*token.unwrap()).clone() 245 } else { 246 panic!("Expected type not found"); 247 } 248 } else if let Some(Token::RParen) = token { 249 if let Token::RParen = exp_type { 250 (*iter) += 1; 251 (*token.unwrap()).clone() 252 } else { 253 panic!("Expected type not found"); 254 } 255 } else if let Some(Token::Semicolon) = token { 256 if let Token::Semicolon = exp_type { 257 (*iter) += 1; 258 (*token.unwrap()).clone() 259 } else { 260 panic!("Expected type not found"); 261 } 262 } else { 263 panic!("Not sure why this would happen"); 264 } 265 } else { 266 (*iter) += 1; 267 (*token.unwrap()).clone() 268 } 269 }; 270 271 let parse_call = |nodes: &mut Vec<CallNode>, tokens: &Vec<Token>, mut iter: &mut usize| { 272 let first_id = consume(tokens, iter, Some(Token::Identifier(String::new()))); 273 let mut target: Option<Token> = None; 274 let mut method = first_id.clone(); 275 276 if matches!(tokens[*iter], Token::Period) { 277 consume(tokens, iter, Some(Token::Period)); 278 target = Some(first_id.clone()); 279 method = consume(tokens, iter, Some(Token::Identifier(String::new()))) 280 } 281 282 consume(tokens, iter, Some(Token::LParen)); 283 let mut args: Vec<CallArg> = Vec::new(); 284 let mut current_token = { 285 if *iter < tokens.len() { 286 Some(&tokens[*iter]) 287 } else { 288 None 289 } 290 }; 291 292 while matches!(current_token, Some(_)) && !matches!(current_token, Some(Token::RParen)) { 293 let arg_token = consume(tokens, iter, Some(Token::Integer(0))); 294 295 match arg_token { 296 Token::Integer(val) => { 297 args.push(CallArg::Integer(val)); 298 }, 299 _ => panic!("invalid") 300 } 301 302 current_token = { 303 if *iter < tokens.len() { 304 Some(&tokens[*iter]) 305 } else { 306 None 307 } 308 }; 309 } 310 311 consume(tokens, iter, Some(Token::RParen)); 312 313 nodes.push(CallNode{ 314 target: { 315 match target { 316 Some(Token::Identifier(id)) => { 317 Some(id.to_owned()) 318 }, 319 Some(_) => panic!("invalid"), 320 None => None 321 } 322 }, 323 method: match method { 324 Token::Identifier(id) => { 325 id.to_owned() 326 }, 327 _ => panic!("invalid") 328 }, 329 args 330 }); 331 }; 332 333 while iter < tokens.len() { 334 parse_call(&mut nodes, &tokens, &mut iter); 335 let current_token = { 336 if iter < tokens.len() { 337 Some(&tokens[iter]) 338 } else { 339 None 340 } 341 }; 342 343 if matches!(current_token, Some(Token::Semicolon)) { 344 consume(&tokens, &mut iter, Some(Token::Semicolon)); 345 } 346 } 347 348 nodes 349 } 350}