openpql-runner 0.1.5

A high-performance Rust implementation of Poker Query Language (PQL), enabling SQL-like queries for poker analysis and calculations. This project is a spiritual successor to the original Java implementation developed by Odds Oracle.
Documentation
// TODO: remove!; tmp implementation
#![cfg_attr(coverage_nightly, coverage(off))]

use super::*;

pub struct PQLRunner {}

impl PQLRunner {
    // TODO: check max selectors
    // TODO: refactor run logic
    // TODO: remove
    #[allow(clippy::missing_panics_doc)]
    pub fn try_run_stmt(stmt: &ast::Stmt<'_>) -> PQLResult<RunnerOutput> {
        let mut rng = rand::rng();
        let mut vm = Vm::from_stmt(stmt)?;
        let n_trails = vm.static_data.n_trails;
        let game = vm.static_data.game;

        let mut output = RunnerOutput::new(game, &stmt.selectors);

        let where_program = match &stmt.where_clause {
            Some(expr) => Some(vm::compile_where(&mut vm, expr)?),
            None => None,
        };

        let programs = stmt
            .selectors
            .iter()
            .map(|s| vm::compile_selector(&mut vm, s))
            .collect::<PQLResult<Vec<_>>>()?;

        while output.n_succ < n_trails {
            if output.n_fail == n_trails {
                // TODO: fix this
                return Err(((0, 1), VmError::SamplingFailed).into());
            }

            match vm.sample(&mut rng) {
                Some(()) => {
                    if let Some(wp) = &where_program {
                        let keep = matches!(
                            wp.execute(&mut vm.as_context())?,
                            VmStackValue::Bool(true)
                        );

                        if !keep {
                            //TODO: refine this
                            output.n_fail += 1;
                            continue;
                        }
                    }

                    for (idx, program) in programs.iter().enumerate() {
                        output.push_value(
                            idx,
                            program.execute(&mut vm.as_context())?,
                        );
                    }
                    output.n_succ += 1;
                }
                None => output.n_fail += 1,
            }
        }

        Ok(output)
    }

    // tmp function
    pub fn run<S: io::Write, T: io::Write>(
        src: &str,
        stream_out: &mut S,
        stream_err: &mut T,
    ) -> io::Result<()> {
        match parse_pql(src) {
            Ok(stmts) => {
                for (i, stmt) in stmts.iter().enumerate() {
                    if i > 0 {
                        writeln!(stream_out, "{:-<80}", "")?;
                    }

                    match Self::try_run_stmt(stmt) {
                        Ok(output) => {
                            output.report_to_stream(stmt, stream_out)?;
                            writeln!(stream_out, "{} trials", output.n_succ)?;
                        }
                        Err(err) => {
                            writeln!(
                                stream_err,
                                "{err:?} {}",
                                &src[err.loc.0..err.loc.1]
                            )?;
                        }
                    }
                }
            }
            Err(err) => writeln!(stream_err, "{err:?}")?,
        }
        Ok(())
    }
}