use std::{collections::HashMap, sync::RwLock};
#[derive(Debug)]
pub struct AST {
pub version: f32, pub globals: RwLock<HashMap<String, String>>, pub vars: RwLock<HashMap<String, String>>, pub subs: HashMap<String, String>, pub person: HashMap<String, String>, pub arrays: HashMap<String, Vec<String>>,
pub topics: HashMap<String, Topic>,
pub objects: HashMap<String, Object>,
}
#[derive(Debug, Clone)]
pub struct Topic {
pub name: String,
pub triggers: Vec<Trigger>,
pub includes: HashMap<String, bool>,
pub inherits: HashMap<String, bool>,
}
impl AST {
pub fn new() -> Self {
Self {
version: 0.0,
globals: RwLock::new(HashMap::new()),
vars: RwLock::new(HashMap::new()),
subs: HashMap::new(),
person: HashMap::new(),
arrays: HashMap::new(),
topics: HashMap::new(),
objects: HashMap::new(),
}
}
pub fn extend(&mut self, other: AST) {
if other.version != 0.0 {
self.version = other.version;
}
let mut global_guard = self.globals.write().expect("RwLock poisoned");
let mut other_globals = other.globals.write().expect("RwLock poisoned");
global_guard.extend(other_globals.drain());
let mut vars_guard = self.vars.write().expect("RwLock poisoned");
let mut other_vars = other.vars.write().expect("RwLock poisoned");
vars_guard.extend(other_vars.drain());
self.subs.extend(other.subs.into_iter());
self.person.extend(other.person.into_iter());
self.arrays.extend(other.arrays.into_iter());
self.objects.extend(other.objects.into_iter());
for (name, topic) in other.topics {
match self.topics.get_mut(&name) {
Some(mine) => {
mine.triggers.extend(topic.triggers);
}
None => {
self.topics.insert(name, topic);
}
}
}
}
pub fn init_topic(&mut self, name: &String) {
if self.topics.contains_key(name) {
return;
}
self.topics.insert(
name.to_string(),
Topic {
name: name.to_string(),
triggers: Vec::new(),
includes: HashMap::new(),
inherits: HashMap::new(),
},
);
}
pub fn has_begin_block(&self) -> bool {
self.topics.contains_key(crate::BEGIN_TOPIC)
}
pub fn has_topic(&self, name: &str) -> bool {
self.topics.contains_key(name)
}
pub fn get_global(&self, name: &str) -> String {
let globals_guard = self.globals.read().expect("RwLock poisoned");
if let Some(value) = globals_guard.get(name) {
return value.to_string();
}
crate::UNDEFINED.to_string()
}
pub fn set_global(&self, name: &str, value: &str) {
let mut globals_guard = self.globals.write().expect("RwLock poisoned");
globals_guard.insert(name.to_string(), value.to_string());
}
pub fn get_bot_var(&self, name: &str) -> String {
let vars_guard = self.vars.read().expect("RwLock poisoned");
if let Some(value) = vars_guard.get(name) {
return value.to_string();
}
crate::UNDEFINED.to_string()
}
pub fn set_bot_var(&self, name: &str, value: &str) {
let mut vars_guard = self.vars.write().expect("RwLock poisoned");
vars_guard.insert(name.to_string(), value.to_string());
}
}
impl Topic {
pub fn set_includes(&mut self, includes: String) {
self.includes.insert(includes.to_string(), true);
}
pub fn set_inherits(&mut self, inherits: String) {
self.inherits.insert(inherits.to_string(), true);
}
pub fn add_trigger(&mut self, trigger: Trigger) {
self.triggers.push(trigger);
}
}
#[derive(Debug, Clone)]
pub struct Trigger {
pub trigger: String,
pub reply: Vec<String>,
pub condition: Vec<Condition>,
pub redirect: String,
pub previous: String,
}
impl Trigger {
pub fn new(trigger: &str) -> Self {
Self {
trigger: trigger.to_string(),
reply: Vec::new(),
condition: Vec::new(),
redirect: String::from(""),
previous: String::from(""),
}
}
pub fn is_populated(&self) -> bool {
self.trigger.len() > 0
}
}
#[derive(Debug, Clone)]
pub struct Condition {
pub left: String,
pub operator: String,
pub right: String,
pub reply: String,
}
#[derive(Debug, Clone)]
pub struct Object {
pub name: String,
pub language: String,
pub code: Vec<String>,
}
impl Object {
pub fn new(name: &str, language: &str, code: Vec<String>) -> Self {
Self {
name: name.to_string(),
language: language.to_string(),
code,
}
}
}