added support for if elif else statements by returning a boolean
from the identifier syntax parsing
This commit is contained in:
@@ -131,6 +131,7 @@ pub fn modify_data // TODO rename
|
||||
character,
|
||||
choices,
|
||||
};
|
||||
debug!("{new_data:?}");
|
||||
queue.push_back(new_data);
|
||||
drop(queue);
|
||||
}
|
||||
|
||||
+10
-1
@@ -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
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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<String, tokenise::Value>,
|
||||
) -> Result<usize,(String,usize)>
|
||||
) -> 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<String, tokenise::Value>
|
||||
)
|
||||
-> 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,
|
||||
}
|
||||
debug!("{variables:?}");
|
||||
sum_index += 1;
|
||||
Ok(sum_index)
|
||||
},
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Mutex<VecDeque<api::DataToSend>>>,
|
||||
labels: &HashMap<String, usize>,
|
||||
variables: &mut HashMap<String, tokenise::Value>,
|
||||
rx: &Receiver<(usize,String)>,
|
||||
)
|
||||
-> Result<usize, String>
|
||||
@@ -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");
|
||||
|
||||
+42
-17
@@ -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<Operator, String>
|
||||
{
|
||||
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<String, String>
|
||||
{
|
||||
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::<i64>().is_ok()
|
||||
{
|
||||
tokenised_data.push(Token::Value(Value::Integer(item.parse::<i64>().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::<i64>().is_ok()
|
||||
{
|
||||
tokenised_data.push(Token::Value(Value::Integer(item.parse::<i64>().unwrap()))); // unwrap is fine here because I checked
|
||||
}
|
||||
// Labels
|
||||
else if item.ends_with(':')
|
||||
{
|
||||
|
||||
+11
-3
@@ -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" {
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user