1#![cfg_attr(coverage_nightly, coverage(off))]
3
4use super::*;
5
6pub struct PQLRunner {}
7
8impl PQLRunner {
9 #[allow(clippy::missing_panics_doc)]
13 pub fn try_run_stmt(stmt: &ast::Stmt<'_>) -> PQLResult<RunnerOutput> {
14 let mut rng = rand::rng();
15 let mut vm = Vm::from_stmt(stmt)?;
16 let n_trails = vm.static_data.n_trails;
17 let game = vm.static_data.game;
18
19 let mut output = RunnerOutput::new(game, &stmt.selectors);
20
21 let where_program = match &stmt.where_clause {
22 Some(expr) => Some(vm::compile_where(&mut vm, expr)?),
23 None => None,
24 };
25
26 for (idx, selector) in stmt.selectors.iter().enumerate() {
27 let program = vm::compile_selector(&mut vm, selector)?;
28 while output.n_succ < n_trails {
29 if output.n_fail == n_trails {
30 return Err(((0, 1), VmError::SamplingFailed).into());
32 }
33
34 match vm.sample(&mut rng) {
35 Some(()) => {
36 if let Some(wp) = &where_program {
37 let keep = matches!(
38 wp.execute(&mut vm.as_context())?,
39 VmStackValue::Bool(true)
40 );
41
42 if !keep {
43 output.n_fail += 1;
45 continue;
46 }
47 }
48
49 output.push_value(
50 idx,
51 program.execute(&mut vm.as_context())?,
52 );
53 output.n_succ += 1;
54 }
55 None => output.n_fail += 1,
56 }
57 }
58 }
59
60 Ok(output)
61 }
62
63 pub fn run<S: io::Write, T: io::Write>(
65 src: &str,
66 stream_out: &mut S,
67 stream_err: &mut T,
68 ) -> io::Result<()> {
69 match parse_pql(src) {
70 Ok(stmts) => {
71 for (i, stmt) in stmts.iter().enumerate() {
72 if i > 0 {
73 writeln!(stream_out, "{:-<80}", "")?;
74 }
75
76 match Self::try_run_stmt(stmt) {
77 Ok(output) => {
78 output.report_to_stream(stmt, stream_out)?;
79 writeln!(stream_out, "{} trials", output.n_succ)?;
80 }
81 Err(err) => {
82 writeln!(
83 stream_err,
84 "{err:?} {}",
85 &src[err.loc.0..err.loc.1]
86 )?;
87 }
88 }
89 }
90 }
91 Err(err) => writeln!(stream_err, "{err:?}")?,
92 }
93 Ok(())
94 }
95}