Cleaned code up a bit
TODD: make colour an enum make unwrap_or_exit return the error
This commit is contained in:
@@ -199,4 +199,4 @@ GOTO label
|
|||||||
| 12 | Failed to open archive | Make sure the story file is a zip archive. |
|
| 12 | Failed to open archive | Make sure the story file is a zip archive. |
|
||||||
| 13 | Unable to setup the characters hashmap. | Make sure the characters.json file exists, is valid JSON and contains valid characters. |
|
| 13 | Unable to setup the characters hashmap. | Make sure the characters.json file exists, is valid JSON and contains valid characters. |
|
||||||
| 14 | Unable to read the main story file. | Make sure the story.ha file exists and is readable. |
|
| 14 | Unable to read the main story file. | Make sure the story.ha file exists and is readable. |
|
||||||
| 15 | | |
|
| 15 | Unable to tokenise data | Make sure your code is correctly formatted |
|
||||||
|
|||||||
Generated
+11
@@ -462,6 +462,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde-patch",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"warp",
|
"warp",
|
||||||
@@ -969,6 +970,16 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-patch"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ba8dcbff6509fa9394810d943e0e9d486a4256c23f6fcea8a58865fbe8260c4"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_core"
|
name = "serde_core"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ unwrap_used = "warn"
|
|||||||
env_logger = "0.11.10"
|
env_logger = "0.11.10"
|
||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde-patch = "0.2.3"
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
tokio = { version = "1.51.0", features = ["rt-multi-thread","macros"] }
|
tokio = { version = "1.51.0", features = ["rt-multi-thread","macros"] }
|
||||||
warp = { version = "0.4.2", features = ["server"] }
|
warp = { version = "0.4.2", features = ["server"] }
|
||||||
|
|||||||
+7
-25
@@ -7,6 +7,7 @@ use crate::{
|
|||||||
info,
|
info,
|
||||||
Deserialize,
|
Deserialize,
|
||||||
Serialize,
|
Serialize,
|
||||||
|
apply_mut,
|
||||||
Mutex,
|
Mutex,
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
@@ -27,7 +28,7 @@ pub struct Character
|
|||||||
torso_shape: String,
|
torso_shape: String,
|
||||||
arm_shape: String,
|
arm_shape: String,
|
||||||
leg_shape: String,
|
leg_shape: String,
|
||||||
hair_color: String,
|
hair_color: String, // TODO RGB enum
|
||||||
clothing: Clothing,
|
clothing: Clothing,
|
||||||
}
|
}
|
||||||
#[derive(Debug,Deserialize,Serialize,Clone,Default)]
|
#[derive(Debug,Deserialize,Serialize,Clone,Default)]
|
||||||
@@ -39,30 +40,11 @@ pub struct Clothing
|
|||||||
shoes: String,
|
shoes: String,
|
||||||
}
|
}
|
||||||
impl Character {
|
impl Character {
|
||||||
// Big ass ugly function because rust doesn't support referencing struct entries by string
|
// Big ass ugly match case
|
||||||
pub fn set_field(&mut self, field: &str, value: &str) -> Result<(), ()> {
|
pub fn set_field(&mut self, field: &str, value: &str) -> Result<(), String> {
|
||||||
match field {
|
let patch = format!("{{ \"{field}\": \"{value}\" }}");
|
||||||
"name" => self.name = value.to_string(),
|
apply_mut(self, patch)
|
||||||
"gender" => self.gender = value.to_string(),
|
.map_err(|_| "Invalid field".to_string())?;
|
||||||
"eye_color" => self.eye_color = value.to_string(),
|
|
||||||
"pronoun_subject" => self.pronoun_subject = value.to_string(),
|
|
||||||
"pronoun_object" => self.pronoun_object = value.to_string(),
|
|
||||||
"pronoun_deppos" => self.pronoun_deppos = value.to_string(),
|
|
||||||
"pronoun_indpos" => self.pronoun_indpos = value.to_string(),
|
|
||||||
"pronoun_reflex" => self.pronoun_reflex = value.to_string(),
|
|
||||||
"head_shape" => self.head_shape = value.to_string(),
|
|
||||||
"hair_style" => self.hair_style = value.to_string(),
|
|
||||||
"torso_shape" => self.torso_shape = value.to_string(),
|
|
||||||
"arm_shape" => self.arm_shape = value.to_string(),
|
|
||||||
"leg_shape" => self.leg_shape = value.to_string(),
|
|
||||||
"hair_color" => self.hair_color = value.to_string(),
|
|
||||||
"clothing.top" => self.clothing.top = value.to_string(),
|
|
||||||
"clothing.bottom" => self.clothing.bottom = value.to_string(),
|
|
||||||
"clothing.shoes" => self.clothing.shoes = value.to_string(),
|
|
||||||
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-16
@@ -27,6 +27,7 @@ use serde::
|
|||||||
Serialize
|
Serialize
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use serde_patch::apply_mut;
|
||||||
use zip::
|
use zip::
|
||||||
{
|
{
|
||||||
ZipArchive,
|
ZipArchive,
|
||||||
@@ -51,17 +52,9 @@ async fn main()
|
|||||||
exit(10);
|
exit(10);
|
||||||
});
|
});
|
||||||
let file = File::open(format!("../stories/{file_name}")) // Get the file
|
let file = File::open(format!("../stories/{file_name}")) // Get the file
|
||||||
.unwrap_or_else
|
.unwrap_or_exit("Failed to read file.", 11);
|
||||||
(|err| {
|
|
||||||
error!("Failed to open file: {err}");
|
|
||||||
exit(11);
|
|
||||||
});
|
|
||||||
let mut archive = ZipArchive::new(file) // Open the archive
|
let mut archive = ZipArchive::new(file) // Open the archive
|
||||||
.unwrap_or_else
|
.unwrap_or_exit("Failed to open archive", 12);
|
||||||
(|err| {
|
|
||||||
error!("Failed to open archive: {err}");
|
|
||||||
exit(12);
|
|
||||||
});
|
|
||||||
// Setup the characters hashmap which will store each character in it as a Character struct
|
// Setup the characters hashmap which will store each character in it as a Character struct
|
||||||
let characters = match character::character_parse(&mut archive)
|
let characters = match character::character_parse(&mut archive)
|
||||||
{
|
{
|
||||||
@@ -102,11 +95,7 @@ async fn main()
|
|||||||
// Read the file and split it into tokens
|
// Read the file and split it into tokens
|
||||||
// file read from a zip file /story.ha
|
// file read from a zip file /story.ha
|
||||||
let mut story_file = archive.by_name("story.ha")
|
let mut story_file = archive.by_name("story.ha")
|
||||||
.unwrap_or_else
|
.unwrap_or_exit("Unable to read story file", 14);
|
||||||
(|err| {
|
|
||||||
error!("Unable to read story file: {err}");
|
|
||||||
exit(14);
|
|
||||||
});
|
|
||||||
let mut file_contents = String::new();
|
let mut file_contents = String::new();
|
||||||
story_file.read_to_string(&mut file_contents)
|
story_file.read_to_string(&mut file_contents)
|
||||||
.unwrap_or_else
|
.unwrap_or_else
|
||||||
@@ -121,11 +110,13 @@ async fn main()
|
|||||||
{
|
{
|
||||||
warn!("No END statement, story may exit unexpectedly");
|
warn!("No END statement, story may exit unexpectedly");
|
||||||
}
|
}
|
||||||
let (tokens, labels,_) = tokenise::tokenise(&space_seperated, 0).unwrap();
|
let (tokens, labels,_) = tokenise::tokenise(&space_seperated, 0)
|
||||||
|
.unwrap_or_exit("Unable to tokenise data", 15);
|
||||||
debug!("{tokens:?}");
|
debug!("{tokens:?}");
|
||||||
let data_clone2 = Arc::clone(&data_to_send);
|
let data_clone2 = Arc::clone(&data_to_send);
|
||||||
let characters_clone2 = Arc::clone(&characters);
|
let characters_clone2 = Arc::clone(&characters);
|
||||||
// Run the parsing process for the DSL
|
// Run the parsing process for the DSL
|
||||||
|
info!("DSL parsing begun");
|
||||||
match parsing::token_parse(&tokens, &characters_clone2, &data_clone2, &rx)
|
match parsing::token_parse(&tokens, &characters_clone2, &data_clone2, &rx)
|
||||||
{
|
{
|
||||||
// Exit with error or success
|
// Exit with error or success
|
||||||
|
|||||||
@@ -20,13 +20,12 @@ mod character_parse;
|
|||||||
// Parse the tokens in a file
|
// Parse the tokens in a file
|
||||||
// Returns success or an error string
|
// Returns success or an error string
|
||||||
pub fn token_parse(
|
pub fn token_parse(
|
||||||
tokens: &Vec<tokenise::Token>,
|
tokens: &[tokenise::Token],
|
||||||
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||||
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
||||||
rx: &Receiver<(bool,usize,String)>,
|
rx: &Receiver<(bool,usize,String)>,
|
||||||
) -> Result<(),String>
|
) -> Result<(),String>
|
||||||
{
|
{
|
||||||
info!("DSL parsing begun");
|
|
||||||
let mut index: usize = 0;
|
let mut index: usize = 0;
|
||||||
if rx.recv().is_err()
|
if rx.recv().is_err()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use crate::
|
|||||||
pub fn character_parse
|
pub fn character_parse
|
||||||
(
|
(
|
||||||
index: usize,
|
index: usize,
|
||||||
tokens: &Vec<tokenise::Token>,
|
tokens: &[tokenise::Token],
|
||||||
character_name: String,
|
character_name: String,
|
||||||
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||||
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
||||||
@@ -44,7 +44,7 @@ pub fn character_parse
|
|||||||
let output = tokenise::get_string_token(tokens, sum_index)
|
let output = tokenise::get_string_token(tokens, sum_index)
|
||||||
.map_err(|err| (err, index))?;
|
.map_err(|err| (err, index))?;
|
||||||
debug!("Saying {output}");
|
debug!("Saying {output}");
|
||||||
api::modify_data(data_to_send, "output".to_string(), output.to_string(), character_name, vec![]);
|
api::modify_data(data_to_send, "output".to_string(), output, character_name, vec![]);
|
||||||
},
|
},
|
||||||
// Change the property of the selected character eg @tim CHANGE name "Bill Buffins"
|
// Change the property of the selected character eg @tim CHANGE name "Bill Buffins"
|
||||||
// will change the character with ID tim to "Bill Buffins"; a character's ID cannot change
|
// will change the character with ID tim to "Bill Buffins"; a character's ID cannot change
|
||||||
@@ -71,7 +71,7 @@ pub fn character_parse
|
|||||||
sum_index += 1;
|
sum_index += 1;
|
||||||
let content = tokenise::get_string_token(tokens, sum_index)
|
let content = tokenise::get_string_token(tokens, sum_index)
|
||||||
.map_err(|err| (err, index))?;
|
.map_err(|err| (err, index))?;
|
||||||
api::modify_data(data_to_send, token.to_lowercase(), content.to_string(), character_name, vec![]);
|
api::modify_data(data_to_send, token.to_lowercase(), content, character_name, vec![]);
|
||||||
},
|
},
|
||||||
// Catch all condition, if the instruction is unrecognised as a
|
// Catch all condition, if the instruction is unrecognised as a
|
||||||
// character command
|
// character command
|
||||||
|
|||||||
+21
-25
@@ -6,28 +6,27 @@ use crate::
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Token
|
pub enum Token
|
||||||
{
|
{
|
||||||
Null,
|
|
||||||
String(String),
|
String(String),
|
||||||
Object(Vec<Token>),
|
Object(Vec<Self>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_string_token(tokens: &Vec<Token>, index: usize)
|
pub fn get_string_token(tokens: &[Token], index: usize)
|
||||||
-> Result<String, String>
|
-> Result<String, String>
|
||||||
{
|
{
|
||||||
match tokens.get(index) {
|
match tokens.get(index) {
|
||||||
Some(Token::String(s)) => return Ok(s.clone()),
|
Some(Token::String(s)) => Ok(s.clone()),
|
||||||
Some(_) => return Err("Unexpected token".to_string()),
|
Some(_) => Err("Unexpected token".to_string()),
|
||||||
None => return Err("File unexpectedly reached termination point".to_string()),
|
None => Err("File unexpectedly reached termination point".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_object_token(tokens: &Vec<Token>, index: usize)
|
pub fn get_object_token(tokens: &[Token], index: usize)
|
||||||
-> Result<&Vec<Token>, String>
|
-> Result<&Vec<Token>, String>
|
||||||
{
|
{
|
||||||
match tokens.get(index) {
|
match tokens.get(index) {
|
||||||
Some(Token::Object(v)) => return Ok(v),
|
Some(Token::Object(v)) => Ok(v),
|
||||||
Some(_) => return Err("Unexpected token".to_string()),
|
Some(_) => Err("Unexpected token".to_string()),
|
||||||
None => return Err("File unexpectedly reached termination point".to_string()),
|
None => Err("File unexpectedly reached termination point".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,10 +41,10 @@ pub fn tokenise(space_seperated: &Vec<&str>, mut index: usize)
|
|||||||
while index < space_seperated.len()
|
while index < space_seperated.len()
|
||||||
{
|
{
|
||||||
let mut item = space_seperated[index].to_string();
|
let mut item = space_seperated[index].to_string();
|
||||||
let mut object: Vec<Token>;
|
let object: Vec<Token>;
|
||||||
if item.starts_with("\"")
|
if item.starts_with('"') // TODO support '
|
||||||
{
|
{
|
||||||
(index, item) = match tokenise_string(&space_seperated, index)
|
(index, item) = match tokenise_string(space_seperated, index)
|
||||||
{
|
{
|
||||||
Some((index,item)) => (index,item),
|
Some((index,item)) => (index,item),
|
||||||
None => exit(1),
|
None => exit(1),
|
||||||
@@ -54,7 +53,7 @@ pub fn tokenise(space_seperated: &Vec<&str>, mut index: usize)
|
|||||||
}
|
}
|
||||||
else if item == "{"
|
else if item == "{"
|
||||||
{
|
{
|
||||||
(object, labels, index) = match tokenise(&space_seperated, index+1) // !WARNING! recursive call
|
(object, labels, index) = match tokenise(space_seperated, index+1) // !WARNING! recursive call
|
||||||
{
|
{
|
||||||
Ok((object,labels,index)) => (object,labels,index),
|
Ok((object,labels,index)) => (object,labels,index),
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
@@ -68,10 +67,10 @@ pub fn tokenise(space_seperated: &Vec<&str>, mut index: usize)
|
|||||||
else { tokenised_data.push(Token::String(item)); }
|
else { tokenised_data.push(Token::String(item)); }
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
return Ok((tokenised_data, labels, 0));
|
Ok((tokenised_data, labels, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tokenise_string(space_seperated: &Vec<&str>, mut index: usize)
|
fn tokenise_string(space_seperated: &[&str], mut index: usize)
|
||||||
-> Option<(usize, String)>
|
-> Option<(usize, String)>
|
||||||
{
|
{
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
@@ -80,18 +79,15 @@ fn tokenise_string(space_seperated: &Vec<&str>, mut index: usize)
|
|||||||
string += chars.as_str();
|
string += chars.as_str();
|
||||||
for item in &space_seperated[index+1..]
|
for item in &space_seperated[index+1..]
|
||||||
{
|
{
|
||||||
if item.ends_with("\"")
|
if item.ends_with('"')
|
||||||
{
|
{
|
||||||
let mut chars = item.chars();
|
let mut chars = item.chars();
|
||||||
chars.next_back();
|
chars.next_back();
|
||||||
string += format!(" {}", chars.as_str()).as_str();
|
string += format!(" {}", chars.as_str()).as_str();
|
||||||
break
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string += format!(" {}", item).as_str();
|
|
||||||
}
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
return Some((index+1,string))
|
return Some((index+1,string))
|
||||||
}
|
}
|
||||||
|
string += format!(" {item}").as_str();
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ use crate::
|
|||||||
exit,
|
exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO support Options
|
||||||
|
// TODO pass error message back
|
||||||
pub trait UnwrapOrExit<T>
|
pub trait UnwrapOrExit<T>
|
||||||
{
|
{
|
||||||
fn unwrap_or_exit(self, error_message: &str, error_code: i32) -> T;
|
fn unwrap_or_exit(self, error_message: &str, error_code: i32) -> T;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@tim says "hello world, it's a good day"
|
@tim says "hello world, it's a good day"
|
||||||
@tim change name "Timothy Fineshooter"
|
@tim change name "Timothy Fineshooter"
|
||||||
|
@tim change boop "Timothy Fineshooter"
|
||||||
@tim to fr
|
@tim to fr
|
||||||
choice "choice numero uno" {
|
choice "choice numero uno" {
|
||||||
@tim animate wave
|
@tim animate wave
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user