1
use std::{fmt::Display, str::FromStr};
2

            
3
use schemars::JsonSchema;
4
use serde::{Deserialize, Serialize};
5
use strum_macros::{Display as StrumDisplay, EnumIter};
6

            
7
#[cfg(feature = "smt")]
8
use crate::solver::adaptors::smt::{IntTheory, MatrixTheory, TheoryConfig};
9

            
10
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
11
pub enum Parser {
12
    #[default]
13
    TreeSitter,
14
    ViaConjure,
15
}
16

            
17
impl Display for Parser {
18
5596
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19
5596
        match self {
20
376
            Parser::TreeSitter => write!(f, "tree-sitter"),
21
5220
            Parser::ViaConjure => write!(f, "via-conjure"),
22
        }
23
5596
    }
24
}
25

            
26
impl FromStr for Parser {
27
    type Err = String;
28

            
29
5612
    fn from_str(s: &str) -> Result<Self, Self::Err> {
30
5612
        match s.trim().to_ascii_lowercase().as_str() {
31
5612
            "tree-sitter" => Ok(Parser::TreeSitter),
32
5220
            "via-conjure" => Ok(Parser::ViaConjure),
33
            other => Err(format!(
34
                "unknown parser: {other}; expected one of: tree-sitter, via-conjure"
35
            )),
36
        }
37
5612
    }
38
}
39

            
40
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
41
pub enum Rewriter {
42
    Naive,
43
    Morph,
44
}
45

            
46
impl Display for Rewriter {
47
5596
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48
5596
        match self {
49
5596
            Rewriter::Naive => write!(f, "naive"),
50
            Rewriter::Morph => write!(f, "morph"),
51
        }
52
5596
    }
53
}
54

            
55
impl FromStr for Rewriter {
56
    type Err = String;
57

            
58
5252
    fn from_str(s: &str) -> Result<Self, Self::Err> {
59
5252
        match s.trim().to_ascii_lowercase().as_str() {
60
5252
            "naive" => Ok(Rewriter::Naive),
61
            "morph" => Ok(Rewriter::Morph),
62
            other => Err(format!(
63
                "unknown rewriter: {other}; expected one of: naive, morph"
64
            )),
65
        }
66
5252
    }
67
}
68

            
69
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
70
pub enum QuantifiedExpander {
71
    Native,
72
    ViaSolver,
73
    ViaSolverAc,
74
}
75

            
76
impl Display for QuantifiedExpander {
77
5608
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78
5608
        match self {
79
28
            QuantifiedExpander::Native => write!(f, "native"),
80
            QuantifiedExpander::ViaSolver => write!(f, "via-solver"),
81
5580
            QuantifiedExpander::ViaSolverAc => write!(f, "via-solver-ac"),
82
        }
83
5608
    }
84
}
85

            
86
impl FromStr for QuantifiedExpander {
87
    type Err = String;
88

            
89
5252
    fn from_str(s: &str) -> Result<Self, Self::Err> {
90
5252
        match s.trim().to_ascii_lowercase().as_str() {
91
5252
            "native" => Ok(QuantifiedExpander::Native),
92
5220
            "via-solver" => Ok(QuantifiedExpander::ViaSolver),
93
5220
            "via-solver-ac" => Ok(QuantifiedExpander::ViaSolverAc),
94
            _ => Err(format!(
95
                "unknown quantified expander: {s}; expected one of: \
96
                 native, via-solver, via-solver-ac"
97
            )),
98
        }
99
5252
    }
100
}
101

            
102
impl QuantifiedExpander {
103
5590
    pub(crate) const fn as_u8(self) -> u8 {
104
5590
        match self {
105
10
            QuantifiedExpander::Native => 0,
106
            QuantifiedExpander::ViaSolver => 1,
107
5580
            QuantifiedExpander::ViaSolverAc => 2,
108
        }
109
5590
    }
110

            
111
570420
    pub(crate) const fn from_u8(value: u8) -> Self {
112
570420
        match value {
113
480
            0 => QuantifiedExpander::Native,
114
            1 => QuantifiedExpander::ViaSolver,
115
569940
            2 => QuantifiedExpander::ViaSolverAc,
116
            _ => QuantifiedExpander::Native,
117
        }
118
570420
    }
119
}
120

            
121
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)]
122
pub enum SatEncoding {
123
    #[default]
124
    Log,
125
    Direct,
126
    Order,
127
}
128

            
129
impl SatEncoding {
130
    pub const fn as_rule_set(self) -> &'static str {
131
        match self {
132
            SatEncoding::Log => "SAT_Log",
133
            SatEncoding::Direct => "SAT_Direct",
134
            SatEncoding::Order => "SAT_Order",
135
        }
136
    }
137
}
138

            
139
impl Display for SatEncoding {
140
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141
        match self {
142
            SatEncoding::Log => write!(f, "log"),
143
            SatEncoding::Direct => write!(f, "direct"),
144
            SatEncoding::Order => write!(f, "order"),
145
        }
146
    }
147
}
148

            
149
impl FromStr for SatEncoding {
150
    type Err = String;
151

            
152
    fn from_str(s: &str) -> Result<Self, Self::Err> {
153
        match s.trim().to_ascii_lowercase().as_str() {
154
            "log" => Ok(SatEncoding::Log),
155
            "direct" => Ok(SatEncoding::Direct),
156
            "order" => Ok(SatEncoding::Order),
157
            other => Err(format!(
158
                "unknown sat-encoding: {other}; expected one of: log, direct, order"
159
            )),
160
        }
161
    }
162
}
163

            
164
#[derive(
165
    Debug,
166
    EnumIter,
167
    StrumDisplay,
168
    PartialEq,
169
    Eq,
170
    Hash,
171
    Clone,
172
    Copy,
173
    Serialize,
174
    Deserialize,
175
    JsonSchema,
176
)]
177
pub enum SolverFamily {
178
    Minion,
179
    Sat(SatEncoding),
180
    #[cfg(feature = "smt")]
181
    Smt(TheoryConfig),
182
}
183

            
184
impl FromStr for SolverFamily {
185
    type Err = String;
186

            
187
5252
    fn from_str(s: &str) -> Result<Self, Self::Err> {
188
5252
        let s = s.trim().to_ascii_lowercase();
189

            
190
5252
        match s.as_str() {
191
5252
            "minion" => Ok(SolverFamily::Minion),
192
900
            "sat" | "sat-log" => Ok(SolverFamily::Sat(SatEncoding::Log)),
193
900
            "sat-direct" => Ok(SolverFamily::Sat(SatEncoding::Direct)),
194
900
            "sat-order" => Ok(SolverFamily::Sat(SatEncoding::Order)),
195
            #[cfg(feature = "smt")]
196
900
            "smt" => Ok(SolverFamily::Smt(TheoryConfig::default())),
197
900
            other => {
198
                // allow forms like `smt-bv-atomic` or `smt-lia-arrays`
199
                #[cfg(feature = "smt")]
200
900
                if other.starts_with("smt-") {
201
900
                    let parts = other.split('-').skip(1);
202
900
                    let mut ints = IntTheory::default();
203
900
                    let mut matrices = MatrixTheory::default();
204
900
                    let mut unwrap_alldiff = false;
205

            
206
1800
                    for token in parts {
207
1800
                        match token {
208
1800
                            "" => {}
209
1800
                            "lia" => ints = IntTheory::Lia,
210
900
                            "bv" => ints = IntTheory::Bv,
211
900
                            "arrays" => matrices = MatrixTheory::Arrays,
212
                            "atomic" => matrices = MatrixTheory::Atomic,
213
                            "nodiscrete" => unwrap_alldiff = true,
214
                            other_token => {
215
                                return Err(format!(
216
                                    "unknown SMT theory option '{other_token}', must be one of bv|lia|arrays|atomic|nodiscrete"
217
                                ));
218
                            }
219
                        }
220
                    }
221

            
222
900
                    return Ok(SolverFamily::Smt(TheoryConfig {
223
900
                        ints,
224
900
                        matrices,
225
900
                        unwrap_alldiff,
226
900
                    }));
227
                }
228
                Err(format!(
229
                    "unknown solver family '{other}', expected one of: minion, sat-log, sat-direct, sat-order, smt[(bv|lia)-(arrays|atomic)][-nodiscrete]"
230
                ))
231
            }
232
        }
233
5252
    }
234
}
235

            
236
impl SolverFamily {
237
27900
    pub const fn as_str(&self) -> &'static str {
238
27900
        match self {
239
23400
            SolverFamily::Minion => "minion",
240
            SolverFamily::Sat(_) => "sat",
241
            #[cfg(feature = "smt")]
242
4500
            SolverFamily::Smt(_) => "smt",
243
        }
244
27900
    }
245
}
246

            
247
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
248
pub struct SolverArgs {
249
    pub timeout_ms: Option<u64>,
250
}