use std::collections::HashMap; use crate:: { // Internal code character, api, tokenise, // Libraries mpsc::Receiver, Arc, Mutex, info, debug, warn, }; mod character_parse; // Parse the tokens in a file // Returns success or an error string pub fn token_parse( tokens: &[tokenise::Token], labels: &HashMap, characters: &Arc>>, data_to_send: &Arc>, rx: &Receiver<(bool,usize,String)>, ) -> Result<(),String> { let mut index: usize = 0; if rx.recv().is_err() { warn!("Some issue with api"); // TODO eh? } info!("Client has connected"); // Run an infinite loop 'parse_loop: loop { debug!("Reading {index}"); // Get the next token let token: String = match tokens.get(index) { Some(tokenise::Token::Keyword(s)) => s.clone(), // Ignore closing braces and jump over opening brace blocks Some(tokenise::Token::Bracket((bracket,new_index))) => { if bracket == &tokenise::Bracket::Closing { index += 1; } else { warn!("Unexpected brace block, jumping over..."); index = new_index + 1; } continue 'parse_loop }, // Handle a character Some(tokenise::Token::Character(character_name)) => // TODO add support for narrator { index = match character_parse::character_parse(index+1,tokens,character_name.clone(),characters,data_to_send) { Ok(increment) => increment, Err((err,increment)) => { warn!("{err}"); increment }, }; continue 'parse_loop } Some(_) => { warn!("Unexpected token"); index += 1; continue 'parse_loop }, None => return Err("File unexpectedly reached termination point".to_string()), }; debug!("{index}: {token}"); // The instructions are related to characters match token.to_lowercase().as_str() { "end" => { info!("END command, exiting"); return Ok(()) // quit successfully }, "choice" => { let choice_indeces = choice_parse(tokens, index, data_to_send)?; debug!("{choice_indeces:?}"); if rx.recv().is_err() { warn!("Error sending choices to client"); } let choice = match rx.recv() { Ok((_,choice,_)) => choice_indeces[choice], Err(err) => { warn!("Error receiving choice from client, defaulting to choice 0 {err}"); 0 } }; index = choice; continue 'parse_loop }, "or" => { info!("OR command, jumping over"); index += 2; let new_index = tokenise::get_closing_index(tokens, index)?; index = new_index; continue 'parse_loop }, // Jump to a particular index based on a label eg GOTO character_check "goto" => { index += 1; let label = tokenise::get_keyword_token(tokens, index)?; index = if let Some(label_index) = labels.get(&label) { *label_index } else { warn!("Label {label} does not exist"); index + 1 }; debug!("Jumping to {index}"); continue 'parse_loop } _ => { warn!("Invalid command: {token}"); index += 1; } } if rx.recv().is_err() { warn!("Some issue with api"); } } } fn choice_parse(tokens: &[tokenise::Token], mut index: usize, data_to_send: &Arc>,) -> Result, String> { let mut next_token: String = "choice".to_string(); let mut choices: Vec = Vec::new(); let mut choice_indeces: Vec = Vec::new(); while next_token == "or" || next_token == "choice" { index += 1; choices.push ( tokenise::get_string_token(tokens, index)? ); index += 1; choice_indeces.push(index+1); index = match tokenise::get_closing_index(tokens,index) { Ok(new_index) => new_index + 1, Err(_) => break, }; next_token = match tokenise::get_keyword_token(tokens, index) { Ok(string) => string, Err(_) => break, } }; api::modify_data(data_to_send, "choice".to_string(), String::new(), String::new(), choices); Ok(choice_indeces) }