diff --git a/server/src/parsing.rs b/server/src/parsing.rs index 782aa5e..d0b5260 100644 --- a/server/src/parsing.rs +++ b/server/src/parsing.rs @@ -60,7 +60,7 @@ pub fn token_parse( // Handle a character Some(tokenise::Token::Character(character_name)) => { - index = match character_parse::character_parse(index+1,tokens,character_name.clone(),characters,happening_queue) + index = match character_parse::character_parse(index+1,tokens,character_name.clone(),characters,happening_queue,&variables) { Ok(increment) => increment, Err((err,increment)) => @@ -83,9 +83,9 @@ pub fn token_parse( }, }; } - Some(_) => + Some(tok) => { - warn!("Unexpected token"); + warn!("Unexpected token, at index {index}, expected character, keyword or identifier, got {tok:?}"); index += 1; }, None => return Err("File unexpectedly reached termination point".to_string()), diff --git a/server/src/parsing/character_parse.rs b/server/src/parsing/character_parse.rs index 43d727d..74cbb45 100644 --- a/server/src/parsing/character_parse.rs +++ b/server/src/parsing/character_parse.rs @@ -25,6 +25,7 @@ pub fn character_parse character_name: String, characters: &Arc>>, happening_queue: &Arc>>, + variables: &HashMap, ) -> Result { let mut sum_index: usize = index; @@ -45,7 +46,7 @@ pub fn character_parse { info!("SAYS command with character {character_name}"); sum_index += 1; - let output = tokenise::get_string_token(tokens, sum_index) + let output = tokenise::get_string_token(tokens, sum_index, variables) .map_err(|err| (err, sum_index))?; debug!("Saying {output}"); api::modify_data(happening_queue, "output".to_string(), output, character_name, vec![]); @@ -58,7 +59,7 @@ pub fn character_parse let feature = tokenise::get_keyword_token(tokens, sum_index) .map_err(|err| (err, sum_index))?; sum_index += 1; - let string = tokenise::get_string_token(tokens, sum_index) + let string = tokenise::get_string_token(tokens, sum_index,variables) .map_err(|err| (err, sum_index))?; info!("CHANGE command with character {character_name} feature {feature}"); let mut characters = characters.lock().unwrap_or_exit("Character Mutex was poisoned",3); diff --git a/server/src/parsing/identifier_parse.rs b/server/src/parsing/identifier_parse.rs index b0a430e..a5ac09d 100644 --- a/server/src/parsing/identifier_parse.rs +++ b/server/src/parsing/identifier_parse.rs @@ -44,6 +44,10 @@ pub fn identifier_parse // Another thing like a choice or an input Err(_) => { + if operator != tokenise::Operator::Assignment // Only assignment is valid here + { + return Err((format!("Unexpected operator: {operator:?} at index {}",sum_index-1),sum_index + 1)) + }; let keyword = tokenise::get_keyword_token(tokens,sum_index) .map_err(|err| (err,sum_index))?; match keyword.to_lowercase().as_str() @@ -51,10 +55,24 @@ pub fn identifier_parse "choice" => { let choice: String; - (sum_index, choice) = keyword_parse::choice_parse(tokens, index+1, happening_queue,rx) + (sum_index, choice) = keyword_parse::choice_parse(tokens, index+1, happening_queue,rx,variables) .map_err(|err| (err,sum_index+1))?; variables.insert(identifier.to_owned(), tokenise::Value::String(choice)); - } + }, + "input" => + { + api::modify_data(happening_queue, "input".to_string(), String::new(), String::new(), Vec::new()); + let input = match rx.recv() + { + Ok((_,input)) => input, + Err(err) => + { + warn!("Error receiving input from client, defaulting to choice \"\" {err}"); + "".to_string() + } + }; + variables.insert(identifier.to_owned(), tokenise::Value::String(input)); + }, _ => { warn!("Unexpected keyword {keyword}"); diff --git a/server/src/parsing/keyword_parse.rs b/server/src/parsing/keyword_parse.rs index 3aca769..d75ad30 100644 --- a/server/src/parsing/keyword_parse.rs +++ b/server/src/parsing/keyword_parse.rs @@ -30,7 +30,7 @@ pub fn keyword_parse( { "choice" => { - (index,_) = choice_parse(tokens, index, happening_queue, rx)?; + (index,_) = choice_parse(tokens, index, happening_queue, rx,variables)?; }, "if" => { @@ -114,6 +114,7 @@ pub fn choice_parse mut index: usize, happening_queue: &Arc>>, rx: &Receiver<(usize,String)>, + variables: &HashMap, ) -> Result<(usize,String), String> { @@ -125,7 +126,7 @@ pub fn choice_parse index += 1; choices.push ( - tokenise::get_string_token(tokens, index)? + tokenise::get_string_token(tokens, index,variables)? ); index += 1; choice_indeces.push(index+1); diff --git a/server/src/parsing/parsing.rs b/server/src/parsing/parsing.rs new file mode 100644 index 0000000..e69de29 diff --git a/server/src/tokenise.rs b/server/src/tokenise.rs index b622ad5..ef53d64 100644 --- a/server/src/tokenise.rs +++ b/server/src/tokenise.rs @@ -28,7 +28,7 @@ pub enum Bracket Closing, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone,PartialEq)] pub enum Operator { // Changing a value @@ -39,7 +39,7 @@ pub enum Operator } // Comparing a value -#[derive(Debug,Clone)] +#[derive(Debug,Clone,PartialEq)] pub enum Comparison { Equate, @@ -60,22 +60,6 @@ pub fn get_operator_token(tokens: &[Token], index: usize) None => Err("File unexpectedly reached termination point".to_string()), } } -pub fn get_string_token(tokens: &[Token], index: usize) --> Result -{ - match tokens.get(index) { - Some(Token::Value(val)) => - { - match val - { - Value::String(s) => Ok(s.clone()), - _ => Err("Unexpected value type".to_string()), - } - }, - Some(tok) => Err(format!("Unexpected token at index {index}, expected string value, got {tok:?}")), - None => Err("File unexpectedly reached termination point".to_string()), - } -} pub fn get_keyword_token(tokens: &[Token], index: usize) -> Result { @@ -112,6 +96,34 @@ pub fn get_identifier_token(tokens: &[Token], index: usize) None => Err("File unexpectedly reached termination point".to_string()), } } +pub fn get_string_token(tokens: &[Token], index: usize, variables: &HashMap) +-> Result +{ + match tokens.get(index) { + // Either get string directly + Some(Token::Value(val)) => + { + match val + { + Value::String(s) => Ok(s.clone()), + _ => Err("Unexpected value type".to_string()), + } + }, + // Or get the string that the identifier references + Some(Token::Identifier(iden)) => + { + let val = variables.get(iden) + .ok_or(format!("Variable {iden} not initialised"))?; + match val + { + Value::String(s) => Ok(s.clone()), + _ => Err("Unexpected value type".to_string()), + } + }, + Some(tok) => Err(format!("Unexpected token at index {index}, expected string value, got {tok:?}")), + None => Err("File unexpectedly reached termination point".to_string()), + } +} // Tokenise the story to Vec // It can contain sub-objects (using recursive calls) diff --git a/stories/story.ha b/stories/story.ha index a9145d8..2c7237f 100644 --- a/stories/story.ha +++ b/stories/story.ha @@ -1,4 +1,6 @@ -@tim says "hello world, it's a good day" +$name = input +@tim says "hello" +@tim says $name $x = 3 $x + 1 if $x == 4 { diff --git a/test-client/main.py b/test-client/main.py index 1ea8056..699213a 100644 --- a/test-client/main.py +++ b/test-client/main.py @@ -44,6 +44,12 @@ def choice(choices): print("Invalid choice, defaulting to 0") requests.post(api_url, json=choice); +def get_input(): + api_url = "http://localhost:20264/input" + input_string = input() + requests.post(api_url, json=input_string); + + # Character outputs text to the user def output(character, text): print(character["name"], "says")