mod ast;
mod eval;
mod expr;
mod parse;
use ast::Entry;
use eval::Eval;
pub use eval::Sample;
use parse::parse_query;
use rand::SeedableRng;
use rand_pcg::Pcg64 as Pcg;
macro_rules! regex {
($re:literal $(,)?) => {{
static RE: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
RE.get_or_init(|| regex::Regex::new($re).unwrap())
}};
}
pub(crate) use regex;
pub fn run_query(input: &str) -> Result<Vec<Sample>, Error> {
let mut state = State::new();
state.run_query(input)
}
#[derive(Debug, Clone)]
pub struct State {
rng: Pcg,
data: Vec<(usize, Entry)>,
}
impl State {
pub fn new() -> Self {
Self::from_rng(Pcg::from_entropy())
}
pub fn with_seed(seed: u64) -> Self {
Self::from_rng(Pcg::seed_from_u64(seed))
}
fn from_rng(rng: Pcg) -> Self {
Self {
rng,
data: Vec::new(),
}
}
}
impl Default for State {
fn default() -> Self {
Self::new()
}
}
impl State {
pub fn run_query(&mut self, input: &str) -> Result<Vec<Sample>, Error> {
let mut ast = parse_query(input)?;
if !self.data.is_empty() {
let mut entries = std::mem::take(&mut self.data);
let last_id = entries.last().map(|(id, _)| *id).unwrap_or(0);
entries.reserve(ast.root.entries.len());
for (id, e) in ast.root.entries {
entries.push((id + last_id + 1, e));
}
debug_assert!(entries.windows(2).all(|w| w[0].0 + 1 == w[1].0));
ast.root.entries = entries;
}
let res = ast.eval(&mut self.rng);
Ok(res)
}
fn push_entry(&mut self, entry: Entry) {
let id = self.data.len();
self.data.push((id, entry));
}
pub fn add_data(&mut self, entry: &str) {
self.push_entry(Entry::data(entry.trim()));
}
pub fn add_entry(&mut self, entry: &str) -> Result<(), Error> {
let entry = Entry::parse(entry.trim())?;
self.push_entry(entry);
Ok(())
}
}
#[derive(Debug)]
pub enum Error {
Options(String),
Expr(String),
ParseQuery(String),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Options(e) => write!(f, "options: {e}"),
Error::Expr(e) => write!(f, "expresions: {e}"),
Error::ParseQuery(e) => write!(f, "query structure: {e}"),
}
}
}
impl std::error::Error for Error {}