use crate::parser::data::Syntax;
use crate::select_and_generate_text;
use crate::CompileError;
use crate::ExtContext;
use crate::RandomNumberGenerator;
use crate::Substitutor;
pub type SyntaxId = usize;
#[derive(Clone, Debug)]
pub struct Generator<
#[cfg(all(feature = "fastrand", feature = "regex"))] R: RandomNumberGenerator = crate::DefaultRng,
#[cfg(not(all(feature = "fastrand", feature = "regex")))] R: RandomNumberGenerator,
#[cfg(feature = "regex")] S: Substitutor = crate::DefaultSubst,
#[cfg(not(feature = "regex"))] S: Substitutor,
> {
syntaxes: Vec<Syntax<S>>,
weights: Vec<f64>,
equalized_chance: bool,
ids: Vec<SyntaxId>,
rng: R,
}
impl<R: RandomNumberGenerator, S: Substitutor> Default for Generator<R, S> {
fn default() -> Self {
Self::new()
}
}
impl<R: RandomNumberGenerator, S: Substitutor> std::str::FromStr for Generator<R, S> {
type Err = CompileError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let syntax: Syntax<S> = s.parse()?;
let mut ph: Generator<R, S> = Generator::new();
ph.add(syntax)?;
Ok(ph)
}
}
impl<R: RandomNumberGenerator, S: Substitutor> Generator<R, S> {
pub fn new() -> Self {
Self {
syntaxes: Vec::new(),
weights: Vec::new(),
equalized_chance: false,
ids: Vec::new(),
rng: R::new(),
}
}
pub fn generate(&mut self) -> String {
let no_context = super::ExtContext::new();
self.generate_with_context(&no_context)
}
pub fn generate_with_context(&mut self, ext_context: &ExtContext) -> String {
select_and_generate_text(
&self.syntaxes,
&self.weights,
self.equalized_chance,
ext_context,
&mut self.rng,
)
}
pub fn add(&mut self, syntax: Syntax<S>) -> Result<SyntaxId, CompileError> {
self.add_with_start_condition(syntax, "main")
}
pub fn add_with_start_condition(
&mut self,
mut syntax: Syntax<S>,
start_condition: &str,
) -> Result<SyntaxId, CompileError> {
syntax.bind_syntax(start_condition)?;
let new_weight = syntax.weight();
self.syntaxes.push(syntax);
self.weights.push(self.weight() + new_weight);
let id = match self.ids.last() {
Some(x) => {
if *x < usize::MAX {
*x + 1
} else {
let mut compile_error = CompileError::new();
compile_error.add_error_message("Too many syntaxes".to_string());
return Err(compile_error);
}
}
None => 1,
};
self.ids.push(id);
Ok(id)
}
pub fn remove(&mut self, syntax_id: SyntaxId) -> Result<(), SyntaxRemoveError> {
let i = match self.ids.binary_search(&syntax_id) {
Ok(x) => x,
Err(_) => return Err(SyntaxRemoveError::new()),
};
self.ids.remove(i);
self.syntaxes.remove(i);
self.weights.pop();
let mut sum: f64 = 0.0;
if i >= 1 {
sum = self.weights[i - 1];
}
for j in i..self.syntaxes.len() {
sum += self.syntaxes[j].weight();
self.weights[j] = sum;
}
Ok(())
}
pub fn clear(&mut self) {
self.syntaxes.clear();
self.weights.clear();
self.ids.clear();
}
pub fn equalize_chance(&mut self, enable: bool) {
self.equalized_chance = enable;
}
pub fn number_of_syntax(&self) -> usize {
self.syntaxes.len()
}
pub fn weight(&self) -> f64 {
if let Some(x) = self.weights.last() {
*x
} else {
0.0
}
}
pub fn combination_number(&self) -> usize {
self.syntaxes
.iter()
.fold(0, |acc, x| acc + x.combination_number())
}
}
#[derive(Clone, Default, Debug)]
pub struct SyntaxRemoveError {}
impl SyntaxRemoveError {
pub fn new() -> Self {
Self {}
}
}
impl std::fmt::Display for SyntaxRemoveError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "error in remove()")?;
Ok(())
}
}
impl std::error::Error for SyntaxRemoveError {}