added support for instring variables and made character IDs

be always stored in lowercase
This commit is contained in:
2026-05-26 21:41:36 +01:00
parent cc3eca857d
commit 148fb73f7f
12 changed files with 69 additions and 70 deletions
+1
View File
@@ -461,6 +461,7 @@ version = "0.0.3"
dependencies = [
"env_logger",
"log",
"regex",
"serde",
"serde-patch",
"serde_json",
+1
View File
@@ -25,6 +25,7 @@ unwrap_used = "warn"
[dependencies]
env_logger = "0.11.10"
log = "0.4.29"
regex = "1.12.3"
serde = { version = "1.0.228", features = ["derive"] }
serde-patch = "0.2.3"
serde_json = "1.0.149"
+5 -2
View File
@@ -71,8 +71,11 @@ pub fn character_parse(archive: &mut ZipArchive<File>)
// Serialise this to a HashMap
let characters: HashMap<String, Character> =
serde_json::from_str(&file_contents)
.map_err (|err| format!("Invalid JSON in characters.json: {err}"))?;
serde_json::from_str::<HashMap<String,Character>>(&file_contents)
.map_err (|err| format!("Invalid JSON in characters.json: {err}"))?
.into_iter()
.map(|(k,v)| (k.to_lowercase(), v))
.collect();
info!("Parsed characters from characters.json");
debug!("{characters:?}");
Ok(Arc::new(Mutex::new(characters)))
+1
View File
@@ -40,6 +40,7 @@ use crate::
{
traits::UnwrapOrExit,
};
use regex::Regex;
#[tokio::main]
async fn main()
+3
View File
@@ -10,6 +10,7 @@ use crate::
VecDeque,
warn,
debug,
info,
mpsc::Receiver,
};
use super::keyword_parse;
@@ -62,6 +63,7 @@ pub fn identifier_parse
"input" =>
{
api::modify_data(happening_queue, "input".to_string(), String::new(), String::new(), Vec::new());
info!("Waiting for client input");
let input = match rx.recv()
{
Ok((_,input)) => input,
@@ -72,6 +74,7 @@ pub fn identifier_parse
}
};
variables.insert(identifier.to_owned(), tokenise::Value::String(input));
sum_index += 1;
},
_ =>
{
+11 -2
View File
@@ -89,6 +89,7 @@ pub fn keyword_parse(
// Jump to a particular index based on a label eg GOTO character_check
"goto" =>
{
info!("GOTO command, jumping there");
index += 1;
let label = tokenise::get_keyword_token(tokens, index)?;
index = if let Some(label_index) = labels.get(&label) { *label_index }
@@ -98,10 +99,17 @@ pub fn keyword_parse(
index + 1
};
debug!("Jumping to {index}");
}
},
"pan" =>
{
info!("PAN command, informing client");
index += 1;
let location = tokenise::get_keyword_token(tokens, index)?;
api::modify_data(happening_queue, "pan".to_string(), location, String::new(), Vec::new());
},
_ =>
{
warn!("Invalid command: {token}");
warn!("Invalid command: {token}, index {index}");
index += 1;
}
}
@@ -142,6 +150,7 @@ pub fn choice_parse
}
};
api::modify_data(happening_queue, "choice".to_string(), String::new(), String::new(), choices.clone());
info!("Waiting for client choice");
debug!("{choice_indeces:?}");
let choice = match rx.recv()
{
+40 -3
View File
@@ -1,6 +1,7 @@
use crate::
{
HashMap,
Regex,
};
#[derive(Debug, Clone)]
@@ -49,6 +50,19 @@ pub enum Comparison
LessOrEqual,
}
impl Value
{
pub fn as_string(&self) -> String
{
match self
{
Value::String(s) => s.clone(),
Value::Integer(i) => i.to_string(),
Value::Bool(b) => b.to_string(),
Value::Null => "".to_string(),
}
}
}
// TODO error reporting for all of these
pub fn get_operator_token(tokens: &[Token], index: usize)
@@ -105,7 +119,11 @@ pub fn get_string_token(tokens: &[Token], index: usize, variables: &HashMap<Stri
{
match val
{
Value::String(s) => Ok(s.clone()),
Value::String(s) =>
{
let string = insert_variables_into_string(s, variables);
Ok(string)
},
_ => Err("Unexpected value type".to_string()),
}
},
@@ -116,7 +134,11 @@ pub fn get_string_token(tokens: &[Token], index: usize, variables: &HashMap<Stri
.ok_or(format!("Variable {iden} not initialised"))?;
match val
{
Value::String(s) => Ok(s.clone()),
Value::String(s) =>
{
let string = insert_variables_into_string(s, variables);
Ok(string)
},
_ => Err("Unexpected value type".to_string()),
}
},
@@ -125,6 +147,19 @@ pub fn get_string_token(tokens: &[Token], index: usize, variables: &HashMap<Stri
}
}
fn insert_variables_into_string(string: &str, variables: &HashMap<String, Value>)
-> String
{
let re = Regex::new(r"\$([A-Za-z0-9-_]*)").unwrap();
re.replace_all(string, |caps: &regex::Captures| {
let key = &caps[1].to_lowercase();
variables.get(key)
.map(|v| v.as_string())
.unwrap_or_else(|| caps[0].to_string()) // leave unchanged if missing
})
.to_string()
}
// Tokenise the story to Vec<Token>
// It can contain sub-objects (using recursive calls)
// TODO check for END
@@ -165,7 +200,7 @@ pub fn tokenise(file_contents: &str)
{
let mut chars = item.chars();
chars.next();
tokenised_data.push(Token::Character(chars.as_str().to_string()));
tokenised_data.push(Token::Character(chars.as_str().to_lowercase().to_string())); // Force character to be lowecase
}
// Strings
else if item.starts_with('"') // TODO support '
@@ -227,6 +262,8 @@ pub fn tokenise(file_contents: &str)
Ok((tokenised_data, labels))
}
// TODO support strings that contain " in them by using a backslash
fn tokenise_string(space_seperated: &[&str], mut index: usize)
-> Option<(usize, String)>
{