From 4f7abb5f1976cd0a4ff32a729e2adebbbbf79f03 Mon Sep 17 00:00:00 2001 From: deadvey Date: Tue, 26 May 2026 11:38:14 +0100 Subject: [PATCH] added support for if elif else statements by returning a boolean from the identifier syntax parsing --- server/src/api.rs | 1 + server/src/main.rs | 11 +++- server/src/parsing.rs | 7 ++- server/src/parsing/identifier_parse.rs | 81 ++++++++++++++++++++----- server/src/parsing/keyword_parse.rs | 56 +++++++++++++++++ server/src/tokenise.rs | 59 ++++++++++++------ stories/story.ha | 14 ++++- stories/test.zip | Bin 939 -> 952 bytes 8 files changed, 189 insertions(+), 40 deletions(-) diff --git a/server/src/api.rs b/server/src/api.rs index 03fb6a1..c9524f5 100644 --- a/server/src/api.rs +++ b/server/src/api.rs @@ -131,6 +131,7 @@ pub fn modify_data // TODO rename character, choices, }; + debug!("{new_data:?}"); queue.push_back(new_data); drop(queue); } diff --git a/server/src/main.rs b/server/src/main.rs index e5bd9e9..e718b78 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -108,9 +108,18 @@ async fn main() error!("Unable to read story file to string: {err}"); exit(14); }); + + // Tokenise the file let (tokens, labels) = tokenise::tokenise(&file_contents) .unwrap_or_exit("Unable to tokenise data", 15); - debug!("{tokens:?}\n{labels:?}"); + // TESTING + //debug!("{tokens:?}\n{labels:?}"); + for (index,token) in tokens.iter().enumerate() + { + debug!("{index}: {token:?}"); + } + + // Run the syntactic parser let characters_clone2 = Arc::clone(&characters); let happening_stack2 = Arc::clone(&happening_stack); // Run the parsing process for the DSL diff --git a/server/src/parsing.rs b/server/src/parsing.rs index cc38a64..bc27ed1 100644 --- a/server/src/parsing.rs +++ b/server/src/parsing.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use crate:: { // Internal code @@ -11,6 +10,7 @@ use crate:: Arc, Mutex, VecDeque, + HashMap, info, debug, warn, @@ -41,10 +41,11 @@ pub fn token_parse( // Get the next token match tokens.get(index) { + // Keyword, eg IF, CHOICE or GOTO Some(tokenise::Token::Keyword(token)) => { if token.to_lowercase().as_str() == "end" { return Ok(()); } - index = keyword_parse::keyword_parse(tokens, token, index, happening_queue, labels, rx)?; + index = keyword_parse::keyword_parse(tokens, token, index, happening_queue, labels, &mut variables, rx)?; }, // Ignore closing braces and jump over opening brace blocks Some(tokenise::Token::Bracket((bracket,new_index))) => @@ -74,7 +75,7 @@ pub fn token_parse( { index = match identifier_parse::identifier_parse(index+1,name,tokens,&mut variables) { - Ok(increment) => increment, + Ok((increment,_)) => increment, Err((err,increment)) => { warn!("{err}"); diff --git a/server/src/parsing/identifier_parse.rs b/server/src/parsing/identifier_parse.rs index db7d044..ada3b1c 100644 --- a/server/src/parsing/identifier_parse.rs +++ b/server/src/parsing/identifier_parse.rs @@ -1,14 +1,9 @@ use crate:: { // Internal code - character, tokenise, - UnwrapOrExit, - parsing, //Libs HashMap, - VecDeque, - info, warn, debug, }; @@ -20,18 +15,40 @@ pub fn identifier_parse identifier: &String, tokens: &[tokenise::Token], variables: &mut HashMap, -) -> Result +) -> Result<(usize,bool),(String,usize)> { let mut sum_index: usize = index; if ! variables.contains_key(identifier) { variables.insert(identifier.to_string(), tokenise::Value::Null); } + let current = variables.get(identifier).unwrap().clone(); let operator = tokenise::get_operator_token(tokens, sum_index) .map_err(|err| (err, sum_index))?; sum_index += 1; - let value = tokenise::get_value_token(tokens, sum_index) - .map_err(|err| (err, sum_index))?; + let mut result = true; + match tokenise::get_value_token(tokens, sum_index) + { + Ok(value) => result = operator_match(¤t,value,operator,identifier,variables), + Err(_) => todo!(), + } + + + sum_index += 1; + Ok((sum_index,result)) +} + +fn operator_match +( + current: &tokenise::Value, + value: tokenise::Value, + operator: tokenise::Operator, + identifier: &String, + variables: &mut HashMap +) +-> bool +{ + // Operator match box match operator { // Changing a value @@ -41,7 +58,6 @@ pub fn identifier_parse } , tokenise::Operator::Add => { - let current = variables.get(identifier).unwrap(); let result: tokenise::Value = match (value.clone(), current) { (tokenise::Value::Integer(int1),tokenise::Value::Integer(int2)) => tokenise::Value::Integer(int1 + int2), @@ -53,20 +69,53 @@ pub fn identifier_parse }, tokenise::Operator::Sub => { - let current = variables.get(identifier).unwrap(); let result: tokenise::Value = match (value.clone(), current) { (tokenise::Value::Integer(int1),tokenise::Value::Integer(int2)) => tokenise::Value::Integer(int2 - int1), _ => value.clone(), // otherwise invalid }; - // TODO comparisons :DDD variables.insert(identifier.to_string(), result); }, - _ => (), + // TODO choice assignment + // TODO input assignment + // TODO comparisons :DDD + tokenise::Operator::Comparison(comp) => + { + let result = match (current, &value) + { + // Integer + (tokenise::Value::Integer(current), tokenise::Value::Integer(comparing)) => + { + match comp + { + tokenise::Comparison::Equate => current == comparing, + tokenise::Comparison::Greater => current > comparing, + tokenise::Comparison::Less => current < comparing, + tokenise::Comparison::GreaterOrEqual => current >= comparing, + tokenise::Comparison::LessOrEqual => current <= comparing, + } + }, + // String + (tokenise::Value::String(current), tokenise::Value::String(comparing)) => + { + match comp + { + tokenise::Comparison::Equate => current == comparing, + tokenise::Comparison::Greater => current > comparing, + tokenise::Comparison::Less => current < comparing, + tokenise::Comparison::GreaterOrEqual => current >= comparing, + tokenise::Comparison::LessOrEqual => current <= comparing, + } + }, + _ => { + warn!("Invalid comparison of {current:?} and {value:?}, evaluating false"); + false + }, + }; + debug!("Comparison {current:?} comp {value:?} evaluates to {result}"); + return result; + } } - debug!("{variables:?}"); - sum_index += 1; - Ok(sum_index) + true } - diff --git a/server/src/parsing/keyword_parse.rs b/server/src/parsing/keyword_parse.rs index 0ae4911..5edd9a8 100644 --- a/server/src/parsing/keyword_parse.rs +++ b/server/src/parsing/keyword_parse.rs @@ -12,6 +12,7 @@ use crate:: info, mpsc::Receiver, }; +use super::identifier_parse; pub fn keyword_parse( tokens: &[tokenise::Token], @@ -19,6 +20,7 @@ pub fn keyword_parse( mut index: usize, happening_queue: &Arc>>, labels: &HashMap, + variables: &mut HashMap, rx: &Receiver<(usize,String)>, ) -> Result @@ -41,6 +43,60 @@ pub fn keyword_parse( }; index = choice; }, + "if" => + { + // TODO can this go in a function? + let mut keyword = "if".to_string(); + while keyword == "if".to_string() || keyword == "elif".to_string() || keyword == "else".to_string() // TODO less beefy?? + { + index += 1; + let mut result: bool = true; + if keyword != "else" + { + let identifier = tokenise::get_identifier_token(tokens, index) + .map(|err| err)?; + (index,result) = match identifier_parse::identifier_parse(index+1, &identifier, tokens, variables) + { + Ok((increment, result)) => (increment,result), + Err((err,increment)) => + { + warn!("{err}"); + (increment,false) + } + } + } + if result { index += 1; break; } + else + { + index = tokenise::get_closing_index(tokens, index) + .map(|err| err)?; + index += 1; + keyword = match tokenise::get_keyword_token(tokens,index) + { + Ok(keyword) => keyword, + Err(_) => break, + } + } + } + }, + "else" => + { + index += 1; + index = tokenise::get_closing_index(tokens, index) + .map(|err| err)?; + }, + "elif" => + { + let current = "elif".to_string(); + loop + { + index += 1; + let Ok(new_index) = tokenise::get_closing_index(tokens, index) + else { continue; }; + index = new_index; + break + } + }, "or" => { info!("OR command, jumping over"); diff --git a/server/src/tokenise.rs b/server/src/tokenise.rs index fa213fd..61afbbb 100644 --- a/server/src/tokenise.rs +++ b/server/src/tokenise.rs @@ -13,7 +13,7 @@ pub enum Token Bracket((Bracket,usize)), // Stores the index of the matching deliminator Character(String), } -#[derive(Debug,Clone)] +#[derive(Debug,Clone,PartialEq)] pub enum Value { String(String), @@ -35,20 +35,28 @@ pub enum Operator Assignment, Add, Sub, - // Comparing a value - Comparison, + Comparison(Comparison), +} + +// Comparing a value +#[derive(Debug,Clone)] +pub enum Comparison +{ + Equate, Greater, Less, GreaterOrEqual, LessOrEqual, } + +// TODO error reporting for all of these pub fn get_operator_token(tokens: &[Token], index: usize) -> Result { match tokens.get(index) { Some(Token::Operator(op)) => Ok(op.clone()), - Some(_) => Err("Unexpected token".to_string()), + Some(tok) => Err(format!("Unexpected token at index {index}, expected operator, got {tok:?}")), None => Err("File unexpectedly reached termination point".to_string()), } } @@ -64,7 +72,7 @@ pub fn get_string_token(tokens: &[Token], index: usize) _ => Err("Unexpected value type".to_string()), } }, - Some(_) => Err("Unexpected token".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()), } } @@ -73,7 +81,7 @@ pub fn get_keyword_token(tokens: &[Token], index: usize) { match tokens.get(index) { Some(Token::Keyword(s)) => Ok(s.clone()), - Some(_) => Err("Unexpected token".to_string()), + Some(tok) => Err(format!("Unexpected token at index {index}, expected keyword, got {tok:?}")), None => Err("File unexpectedly reached termination point".to_string()), } } @@ -82,7 +90,7 @@ pub fn get_closing_index(tokens: &[Token], index: usize) { match tokens.get(index) { Some(Token::Bracket((_, index))) => Ok(*index), // TODO check for closing - Some(_) => Err("Unexpected token".to_string()), + Some(tok) => Err(format!("Unexpected token at index {index}, expected opening brace, got {tok:?}")), None => Err("File unexpectedly reached termination point".to_string()), } } @@ -91,7 +99,16 @@ pub fn get_value_token(tokens: &[Token], index: usize) { match tokens.get(index) { Some(Token::Value(val)) => Ok(val.clone()), - Some(_) => Err("Unexpected token".to_string()), + Some(tok) => Err(format!("Unexpected token at index {index}, expected value (int, string or boolean), got {tok:?}")), + None => Err("File unexpectedly reached termination point".to_string()), + } +} +pub fn get_identifier_token(tokens: &[Token], index: usize) +-> Result +{ + match tokens.get(index) { + Some(Token::Identifier(s)) => Ok(s.clone()), + Some(tok) => Err(format!("Unexpected token at index {index}, expected identifier, got {tok:?}")), None => Err("File unexpectedly reached termination point".to_string()), } } @@ -118,11 +135,11 @@ pub fn tokenise(file_contents: &str) "=" => Some(Operator::Assignment), "+" => Some(Operator::Add), "-" => Some(Operator::Sub), - "==" => Some(Operator::Comparison), - ">" => Some(Operator::Greater), - "<" => Some(Operator::Less), - ">=" => Some(Operator::GreaterOrEqual), - "<=" => Some(Operator::LessOrEqual), + "==" => Some(Operator::Comparison(Comparison::Equate)), + ">" => Some(Operator::Comparison(Comparison::Greater)), + "<" => Some(Operator::Comparison(Comparison::Less)), + ">=" => Some(Operator::Comparison(Comparison::GreaterOrEqual)), + "<=" => Some(Operator::Comparison(Comparison::LessOrEqual)), _ => None, }; match op @@ -151,6 +168,18 @@ pub fn tokenise(file_contents: &str) item = new_item; tokenised_data.push(Token::Value(Value::String(item))); } + else if item.parse::().is_ok() + { + tokenised_data.push(Token::Value(Value::Integer(item.parse::().unwrap()))); // unwrap is fine here because I checked + } + else if item == "true" + { + tokenised_data.push(Token::Value(Value::Bool(true))); + } + else if item == "false" + { + tokenised_data.push(Token::Value(Value::Bool(false))); + } // variable/identifier else if item.starts_with("$") { @@ -159,10 +188,6 @@ pub fn tokenise(file_contents: &str) tokenised_data.push(Token::Identifier(chars.as_str().to_string())); } // Integer - else if item.parse::().is_ok() - { - tokenised_data.push(Token::Value(Value::Integer(item.parse::().unwrap()))); // unwrap is fine here because I checked - } // Labels else if item.ends_with(':') { diff --git a/stories/story.ha b/stories/story.ha index 9f817eb..a9145d8 100644 --- a/stories/story.ha +++ b/stories/story.ha @@ -1,10 +1,18 @@ @tim says "hello world, it's a good day" -@tim change name "Timothy Fineshooter" $x = 3 $x + 1 -$x - 2 +if $x == 4 { + @tim says "5" +} +elif $x < 5 { + + @tim says "<5" +} +else { + @tim says "whar" +} label: -choice "choice numero uno" { +$choice_string = choice "choice numero uno" { @tim says "super sad" } or "choice numero duo" { diff --git a/stories/test.zip b/stories/test.zip index e13f4ea7de647f0635dde629a7b98bccd8b758d5..bb2c4518425b6d7fd5b28d249954bfe52e9d050e 100644 GIT binary patch delta 309 zcmZ3@zJt9!z?+#xgn@y9gTXjrSInhg@rhd*7#N}%K_W5?#U=Sgm3kS8p&^_M%uV^C zS>ZXNS)~=+42&!C$rL}}kyu0sX_E$7b$^DKPesK02hN2}bISK1yqNzxvhC&_0C z-oJZI?1+>9=G~j`zY%jZ|FG!ugRMqw7bY1OG1tq6$uWseY!Q)7e<|$#hAlGr^cUH~ z4?1k)bTsP}CDZeloq6&6MAh%}=a;jtPfLjAHji+-GsSYlmNlN!U%hI+yzP~LzwM7D zW@e`Z7pdBDfBLvECjPWy@0~dl3L87hCUW}yv<#Unm|^0wSo_l)RZ-SM-+$XZuCd(6 t5B2xPk9!$;QG7mmH`tCJrvSuuW}EX^FkC^fl&*_3TP69WSS0|0$Wc%c9Q delta 310 zcmdnNzM8#0z?+#xgn@y9gTYN`XUvv-hmsWx3=DFNAQ2gc;*$KLO1+H4&=5`r=8(n0 zSs+|m!Og(P@`9Ox0Zf$k?dD=K6miLZAI{^rA%J_UaEtDhOQ+;JW}jA@@We~*h0?#> zyOlVauFgz4XW(1N82MfD)TZxEvsLoN3R3H*Exgz%A#qnb>sV5D=^Kea_BN~C3P-^gC?OT@2hS^1j{l7`2#jtFIc`gN$zd#&hozDMmF+5DQMTpv14e)e1Cy7qEKX;=SA zU$STXI=jjVKX=5 o21Z^KuTMU~qy+No