use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, OnceLock, RwLock};
use crate::error::{Error, ErrorKind};
use crate::Result;
pub struct Builder {
terminals: Vec<SymbolDescription>,
productions: Vec<SymbolDescription>
}
impl Builder {
pub fn with_terminal<S: AsRef<str>>(mut self, name: S, description: Option<S>) -> Self {
let symbol = SymbolDescription {
name: name.as_ref().to_string(),
description: description.map(|s| s.as_ref().to_string())
};
self.terminals.push(symbol);
self
}
pub fn with_production<S: AsRef<str>>(mut self, name: S, description: Option<S>) -> Self {
let symbols = SymbolDescription {
name: name.as_ref().to_string(),
description: description.map(|s| s.as_ref().to_string())
};
self.productions.push(symbols);
self
}
pub fn register<S: AsRef<str>>(self, name: S) -> Result<Arc<SystemFamily>> {
let name = name.as_ref();
let mut map = reference().write()?;
if map.contains_key(name) {
return Err(Error::new(ErrorKind::Duplicate,
format!("family name [{}] is already taken", name)));
}
let family = self.build(name)?;
map.insert(name.to_string(), Arc::new(family));
Ok(map.get(name).unwrap().clone())
}
pub fn build<S: AsRef<str>>(self, name: S) -> Result<SystemFamily> {
let name = name.as_ref();
if name.trim().is_empty() {
return Err(Error::new(ErrorKind::Definitions, "family name cannot be empty"));
}
Ok(SystemFamily {
name: name.to_string(),
terminals: self.terminals.into_iter().collect(),
productions: self.productions.into_iter().collect()
})
}
}
#[derive(Debug, Clone)]
pub struct SystemFamily {
name: String,
terminals: HashMap<String, SymbolDescription>,
productions: HashMap<String, SymbolDescription>
}
impl SystemFamily {
pub fn define() -> Builder {
Builder { terminals: Vec::new(), productions: Vec::new() }
}
pub fn name(&self) -> &String {
&self.name
}
pub fn terminals(&self) -> impl Iterator<Item=&SymbolDescription> {
self.terminals.values()
}
pub fn productions(&self) -> impl Iterator<Item=&SymbolDescription> {
self.productions.values()
}
pub fn symbols(&self) -> impl Iterator<Item=&SymbolDescription> {
self.terminals().chain(self.productions())
}
}
pub fn get_family<S: AsRef<str>>(name: S) -> Option<Arc<SystemFamily>> {
let map = reference().read().ok()?;
map.get(name.as_ref()).cloned()
}
pub fn get_or_init_family<S, F>(name: S, default: F) -> Arc<SystemFamily>
where S: AsRef<str>,
F: FnOnce() -> SystemFamily
{
if let Some(value) = get_family(name.as_ref()) {
return value;
}
let mut map = reference().write().unwrap();
if let Some(value) = map.get(name.as_ref()) {
return value.clone();
}
let family = default();
let family = Arc::new(family);
map.insert(name.as_ref().to_string(), family.clone());
family
}
pub fn family_exists<S: AsRef<str>>(name: S) -> bool {
get_family(name).is_some()
}
fn reference() -> &'static RwLock<HashMap<String, Arc<SystemFamily>>> {
static REGISTRY : OnceLock<RwLock<HashMap<String, Arc<SystemFamily>>>> = OnceLock::new();
REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
}
pub fn register(family: SystemFamily) -> Result<Arc<SystemFamily>> {
let name = family.name().clone();
let mut map = reference().write()?;
if map.get(&name).is_some() {
return Err(Error::new(ErrorKind::Duplicate, format!("family {name} has already been registered")));
}
let family = Arc::new(family);
map.insert(name.to_string(), family.clone());
Ok(family)
}
pub trait TryIntoFamily {
fn into_family(self) -> Result<Arc<SystemFamily>>;
}
impl TryIntoFamily for Arc<SystemFamily> {
fn into_family(self) -> Result<Arc<SystemFamily>> {
Ok(self.clone())
}
}
impl TryIntoFamily for SystemFamily {
fn into_family(self) -> Result<Arc<SystemFamily>> {
Ok(Arc::new(self))
}
}
impl TryIntoFamily for &str {
fn into_family(self) -> Result<Arc<SystemFamily>> {
get_family(self).ok_or_else(||
Error::definition(format!("family {self} has not been registered")))
}
}
impl TryIntoFamily for String {
fn into_family(self) -> Result<Arc<SystemFamily>> {
self.as_str().into_family()
}
}
#[derive(Debug, Clone)]
pub struct SymbolDescription {
pub name: String,
pub description: Option<String>
}
impl FromIterator<SymbolDescription> for HashMap<String, SymbolDescription> {
fn from_iter<T: IntoIterator<Item=SymbolDescription>>(iter: T) -> Self {
let mut result = HashMap::new();
for i in iter {
result.insert(i.name.clone(), i);
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::interpretation::abop;
#[test]
fn empty_name() {
let result = SystemFamily::define()
.register("");
assert!(result.is_err());
let result = SystemFamily::define()
.register("bob");
assert!(result.is_ok());
}
#[test]
fn can_register() {
let result = SystemFamily::define()
.with_terminal("surname", Some("It's a surname"))
.with_production("Company", None)
.register("NameSystems")
.unwrap();
assert_eq!(result.terminals.len(), 1);
assert_eq!(result.productions.len(), 1);
assert_eq!(result.name(), "NameSystems");
let surname = result.terminals.get("surname").unwrap();
assert_eq!(surname.name, "surname");
assert!(surname.description.is_some());
assert_eq!(surname.description.as_ref().unwrap(), "It's a surname");
}
#[test]
fn abop_available() {
let abop = get_or_init_family("ABOP", abop::abop_family);
assert_eq!(abop.name(), "ABOP");
}
}