isabelle_client/
process.rs

1use std::{
2    collections::HashMap,
3    io,
4    path::PathBuf,
5    process::{Output, Stdio},
6};
7use tokio::process::Command;
8
9/// Arguments for running the raw ML process in batch mode.
10#[derive(Default)]
11pub struct ProcessArgs {
12    /// The theories to load (-T). Multiple theories are loaded in the given order.
13    pub theories: Vec<String>,
14    // Include session directories (-d)
15    pub session_dirs: Vec<String>,
16    /// The The logic session name (default is ISABELLE_LOGIC="HOL")
17    pub logic: Option<String>,
18    /// Override Isabelle system options for this process (-d).
19    /// Use [OptionsBuilder] to construct options.
20    pub options: HashMap<String, String>,
21}
22
23impl ProcessArgs {
24    pub fn load_theories(ths: &[String]) -> Self {
25        Self {
26            theories: ths.to_vec(),
27            ..Default::default()
28        }
29    }
30}
31
32/// Runs the raw ML process in batch mode.
33/// Arguments for the command are specified in [ProcessArgs].
34/// Returns the process' output.
35///
36/// # Example
37///
38/// ```rust
39/// use isabelle_client::process::{batch_process, ProcessArgs};
40/// use tokio_test;
41/// # tokio_test::block_on(async {
42///
43///
44/// let args = ProcessArgs::load_theories(&[String::from("~~/src/HOL/Examples/Drinker")]);
45/// let output = batch_process(&args, None).await;
46/// assert!(output.unwrap().status.success());
47/// })
48/// ```
49pub async fn batch_process(
50    args: &ProcessArgs,
51    current_dir: Option<&PathBuf>,
52) -> io::Result<Output> {
53    let mut isabelle_cmd = Command::new("isabelle");
54
55    isabelle_cmd
56        .arg("process")
57        .stderr(Stdio::piped())
58        .stdout(Stdio::piped());
59
60    if let Some(cd) = current_dir {
61        isabelle_cmd.current_dir(cd);
62    }
63
64    for t in &args.theories {
65        isabelle_cmd.arg("-T").arg(t);
66    }
67    for d in &args.session_dirs {
68        isabelle_cmd.arg("-d").arg(d);
69    }
70
71    if let Some(l) = &args.logic {
72        isabelle_cmd.arg("-l").arg(l);
73    }
74
75    for (k, v) in args.options.iter() {
76        isabelle_cmd.arg("-o").arg(format!("{}={}", k, v));
77    }
78
79    isabelle_cmd.spawn()?.wait_with_output().await
80}
81
82/// Builder that conveniently allows to specify common Isabelle options.
83#[derive(Default)]
84pub struct OptionsBuilder {
85    options: HashMap<String, String>,
86}
87
88impl From<OptionsBuilder> for HashMap<String, String> {
89    /// Consumes the builder and return a key value map of the specified options.
90    fn from(val: OptionsBuilder) -> Self {
91        val.options
92    }
93}
94
95impl OptionsBuilder {
96    pub fn new() -> Self {
97        Self {
98            ..Default::default()
99        }
100    }
101
102    fn add_int_option(&mut self, k: &str, v: isize) -> &mut Self {
103        self.options.insert(k.to_owned(), v.to_string());
104        self
105    }
106
107    fn add_bool_option(&mut self, k: &str, v: bool) -> &mut Self {
108        self.options.insert(k.to_owned(), v.to_string());
109        self
110    }
111
112    fn add_real_option(&mut self, k: &str, v: f32) -> &mut Self {
113        self.options
114            .insert(k.to_owned(), v.to_string().to_lowercase());
115        self
116    }
117
118    /// Maximum number of worker threads for prover process (0 = hardware max.)
119    pub fn threads(&mut self, threads: isize) -> &mut Self {
120        self.add_int_option("threads", threads)
121    }
122
123    /// Maximum stack size for worker threads (in giga words, 0 = unlimited)
124    pub fn thread_stack_limit(&mut self, limit: f32) -> &mut Self {
125        self.add_real_option("threads_stack_limit", limit)
126    }
127
128    /// Approximative limit for parallel tasks (0 = unlimited)
129    pub fn parallel_limit(&mut self, limit: isize) -> &mut Self {
130        self.add_int_option("parallel_limit", limit)
131    }
132
133    /// Level of parallel proof checking: 0, 1, 2
134    pub fn parallel_proofs(&mut self, limit: isize) -> &mut Self {
135        self.add_int_option("parallel_proofs", limit)
136    }
137
138    /// Scale factor for timeout in Isabelle/ML and session build
139    pub fn timeout_scale(&mut self, scale: f32) -> &mut Self {
140        self.add_real_option("timeout_scale", scale)
141    }
142
143    // "Detail of Proof Checking"
144
145    /// Level of proofterm recording: 0, 1, 2, negative means unchanged
146    pub fn record_proofs(&mut self, level: isize) -> &mut Self {
147        self.add_int_option("record_proofs", level)
148    }
149
150    /// If true then some tools will OMIT some proofs
151    pub fn quick_and_dirty(&mut self, flag: bool) -> &mut Self {
152        self.add_bool_option("quick_and_dirty", flag)
153    }
154
155    /// If true then skips over proofs (implicit 'sorry')
156    pub fn skip_proofs(&mut self, flag: bool) -> &mut Self {
157        self.add_bool_option("skip_proofs", flag)
158    }
159
160    // "Global Session Parameters"
161
162    /// Timeout for session build job (seconds > 0)
163    pub fn timeout(&mut self, limit: f32) -> &mut Self {
164        self.add_real_option("timeout", limit)
165    }
166
167    // Observe timeout for session build (default 'true')
168    pub fn timeout_build(&mut self, flag: bool) -> &mut Self {
169        self.add_bool_option("timeout_build", flag)
170    }
171
172    /// Build process output limit (in million characters, 0 = unlimited)
173    pub fn process_output_limit(&mut self, limit: isize) -> &mut Self {
174        self.add_int_option("process_output_limit", limit)
175    }
176
177    /// Build process output tail shown to user (in lines, 0 = unlimited)
178    pub fn process_output_tail(&mut self, tail: isize) -> &mut Self {
179        self.add_int_option("process_output_tail", tail)
180    }
181
182    // "PIDE Build"
183
184    // Report PIDE markup (in ML) (default 'true')
185    pub fn pide_reports(&mut self, flag: bool) -> &mut Self {
186        self.add_bool_option("pide_reports", flag)
187    }
188
189    // Report PIDE markup (in batch build) (default 'true')
190    pub fn build_pide_reports(&mut self, flag: bool) -> &mut Self {
191        self.add_bool_option("build_pide_reports", flag)
192    }
193}