use std::collections::HashSet;
use std::ops::Deref;
use std::sync::RwLock;
use crate::error::{Error, ErrorKind};
use crate::prelude::*;
use crate::productions::{Production, ProductionStore};
use crate::system::family::TryIntoFamily;
use crate::symbols::{get_code, SymbolStore};
use crate::symbols::iterator::SymbolIterable;
use super::{parser, Result, symbols};
pub mod family;
#[derive(Debug)]
pub struct System {
symbols: RwLock<HashSet<u32>>,
productions: RwLock<Vec<Production>>
}
impl System {
pub fn new() -> Self {
System {
symbols: RwLock::new(HashSet::new()),
productions: RwLock::new(Vec::new())
}
}
pub fn of_family<F: TryIntoFamily>(family: F) -> Result<Self> {
let family = family.into_family()?;
let system = System::default();
for symbol in family.symbols() {
system.add_symbol(symbol.name.as_str())?;
}
Ok(system)
}
pub fn parse_production(&self, production: &str) -> Result<Production> {
let prod = parser::parse_production(production)?;
let mut map = self.symbols.write()?;
prod.all_symbols_iter().for_each(|s| {
map.insert(s.code());
});
self.add_production(prod)
}
pub fn derive_once(&self, string: ProductionString) -> Result<ProductionString> {
if string.is_empty() {
return Ok(ProductionString::empty())
}
if let Ok(productions) = self.productions.read() {
return derive_once(string, productions.deref());
}
Err(Error::general("Poisoned lock on production list"))
}
pub fn derive(&self, string: ProductionString, settings: RunSettings) -> Result<ProductionString> {
if string.is_empty() {
return Ok(ProductionString::empty())
}
if let Ok(productions) = self.productions.read() {
return derive(string, productions.deref(), settings);
}
Err(Error::general("Poisoned lock on production list"))
}
pub fn production_len(&self) -> usize {
self.productions.read().unwrap().len()
}
pub fn symbol_len(&self) -> usize {
self.symbols.read().unwrap().len()
}
}
impl SymbolStore for System {
fn add_symbol(&self, name: &str) -> Result<Symbol> {
let code = symbols::get_code(name)?;
let mut map = self.symbols.write()?;
map.insert(code);
Ok(Symbol::from_code(code))
}
fn get_symbol(&self, name: &str) -> Option<Symbol> {
let code = get_code(name).ok()?;
let symbols = self.symbols.read().ok()?;
symbols.get(&code)
.cloned()
.map(Symbol::from_code)
}
}
impl ProductionStore for System {
fn add_production(&self, production: Production) -> Result<Production> {
let lock = self.productions.write();
if let Ok(mut productions) = lock {
let head = production.head().clone();
match productions.iter_mut().find(|p| (*p.head()).eq(&head)) {
None => productions.push(production),
Some(found) => {
found.merge(production);
}
}
return Ok(productions.iter().find(|p| (*p.head()).eq(&head)).unwrap().clone())
}
Err(Error::new(ErrorKind::Locking, "production lock is poisoned"))
}
}
impl Default for System {
fn default() -> Self {
System::new()
}
}
#[derive(Debug, Clone)]
pub struct RunSettings {
pub max_iterations: usize
}
impl RunSettings {
pub fn for_max_iterations(max_iterations: usize) -> Self {
RunSettings { max_iterations }
}
}
impl From<usize> for RunSettings {
fn from(value: usize) -> Self {
RunSettings::for_max_iterations(value)
}
}
const DEFAULT_MAX_ITERATIONS : usize = 10;
impl Default for RunSettings {
fn default() -> Self {
RunSettings {
max_iterations: DEFAULT_MAX_ITERATIONS
}
}
}
pub fn find_matching<'a>(productions: &'a [Production],
string: &ProductionString, index: usize) -> Option<&'a Production> {
for production in productions {
if production.matches(string, index) {
return Some(production)
}
}
None
}
pub fn derive_once(string: ProductionString, productions: &[Production]) -> Result<ProductionString> {
if string.is_empty() {
return Ok(ProductionString::empty())
}
let mut result = ProductionString::default();
for (index, symbol) in string.symbols().iter().enumerate() {
if let Some(production) = find_matching(productions, &string, index) {
let body = production.body()?;
body.string()
.symbols()
.iter()
.cloned()
.for_each(|symbol| result.push_symbol(symbol));
continue;
} else {
result.push_symbol(*symbol);
}
}
match result.len() {
0 => Ok(ProductionString::empty()),
_ => Ok(result)
}
}
pub fn derive(string: ProductionString, productions: &[Production], settings: RunSettings) -> Result<ProductionString> {
if string.is_empty() {
return Ok(ProductionString::empty())
}
let mut current = string;
for _ in 0..settings.max_iterations {
current = derive_once(current, productions)?;
}
Ok(current)
}
#[cfg(test)]
mod tests {
use std::thread;
use crate::parser::parse_prod_string;
use super::*;
#[test]
fn handles_empty_production() {
let system = System::new();
assert!(system.parse_production("").is_err());
}
#[test]
fn handles_no_head() {
let system = System::new();
assert!(system.parse_production("-> surname surname").is_err());
}
#[test]
fn handles_no_body() {
let system = System::new();
assert!(system.parse_production("Company ->").is_ok());
}
#[test]
fn handles_correct() {
let system = System::new();
assert!(system.parse_production("Company -> surname surname").is_ok());
}
#[test]
fn increments_for_distinct_names() {
let system = System::new();
let symbol1 = system.add_symbol("one").unwrap();
let symbol2 = system.add_symbol("two").unwrap();
assert_ne!(symbol1.code(), symbol2.code());
}
#[test]
fn no_increments_for_equal_names() {
let system = System::new();
let symbol1 = system.add_symbol("one").unwrap();
let symbol2 = system.add_symbol("one").unwrap();
assert_eq!(symbol1.code(), symbol2.code());
}
#[test]
fn sync_and_send() {
let mut symbol1 : Option<Symbol> = None;
let mut symbol2: Option<Symbol> = None;
let system = System::new();
thread::scope(|s| {
s.spawn(|| {
symbol1 = Some(system.add_symbol("one").unwrap());
});
s.spawn(|| {
symbol2 = Some(system.add_symbol("two").unwrap());
});
});
let symbol1 = symbol1.unwrap();
let symbol2 = symbol2.unwrap();
assert_ne!(symbol1.code(), symbol2.code());
}
#[test]
fn can_derive_once() {
let system = System::new();
system.parse_production("Company -> surname Company").expect("Unable to add production");
let string = parse_prod_string("Company").expect("Unable to create string");
let result = system.derive_once(string).unwrap();
assert_eq!(result. len(), 2);
}
#[test]
fn can_derive_multiple_times() {
let system = System::new();
system.parse_production("Company -> surname Company").expect("Unable to add production");
let string = parse_prod_string("Company").expect("Unable to create string");
let result = system.derive(string, RunSettings::for_max_iterations(2)).expect("Unable to derive");
assert_eq!(result.len(), 3);
}
#[test]
fn test_format() {
let system = System::default();
let symbol = system.add_symbol("a").unwrap();
assert_eq!(symbol.to_string(), "a");
let string = parse_prod_string("a b c").unwrap();
assert_eq!(string.to_string(), "a b c");
}
#[test]
fn test_counting_symbols() {
let system = System::default();
assert_eq!(system.symbol_len(), 0);
system.add_symbol("a").unwrap();
assert_eq!(system.symbol_len(), 1);
assert_eq!(system.production_len(), 0);
system.add_symbol("a").unwrap();
assert_eq!(system.symbol_len(), 1);
system.add_symbol("b").unwrap();
assert_eq!(system.symbol_len(), 2);
system.add_symbol("c").unwrap();
assert_eq!(system.symbol_len(), 3);
assert_eq!(system.production_len(), 0);
}
#[test]
fn test_counting_productions() {
let system = System::default();
assert_eq!(system.symbol_len(), 0);
assert_eq!(system.production_len(), 0);
system.parse_production("F -> F F").unwrap();
assert_eq!(system.symbol_len(), 1);
assert_eq!(system.production_len(), 1);
}
#[test]
fn testing_context_sensitive() {
let system = System::default();
let string = parse_prod_string("G S S S X").unwrap();
system.parse_production("G > S -> ").unwrap();
system.parse_production("G < S -> S G").unwrap();
let string = system.derive_once(string).unwrap();
assert_eq!(string, parse_prod_string("S G S S X").unwrap());
let string = system.derive_once(string).unwrap();
assert_eq!(string, parse_prod_string("S S G S X").unwrap());
let string = system.derive_once(string).unwrap();
assert_eq!(string, parse_prod_string("S S S G X").unwrap());
}
}